NOTEBOOK - Stéphane Srsa
PROJET 10
Détectez des faux billets avec Python
SOMMAIRE
3 - Régression linéaire : Modèle prédictif pour remplacer les Nan dans 'margin_low'
3.2- Librairie Statsmodels pour régression linéaire simple et multiple
3.3 - Librairie Sklearn pour régression linéaire multiple - Choix d'un prétraitement si nécessaire
3.4 - Validation du nombre de variables prédictives à utiliser
3.5 - Modèle retenu et Imputation des valeurs de 'margin_low' dans DF_NaN (sklearn)
4 - Analyses et métriques sur les modèles avec ou sans Intercept
4.1 - Comparaison des modèles avec et sans Intercept (Statsmodels)
4.3 - Validation et utilisation du modèle pour remplacer les valeurs manquantes
5.2 - Création du modèle K-means en utilisant train_test_split
7.1 - Choix de l'algorithme pour l'outil d'identification des billets
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import seaborn as sns
from IPython.display import display, HTML
from tabulate import tabulate
import math
# Librairie Sklearn
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error, mean_absolute_percentage_error
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, r2_score
from sklearn.metrics import davies_bouldin_score, adjusted_rand_score, calinski_harabasz_score
from sklearn.manifold import TSNE
from statsmodels.stats.outliers_influence import variance_inflation_factor
from sklearn.model_selection import learning_curve
from sklearn.metrics import make_scorer
from sklearn.metrics import silhouette_score
from sklearn import preprocessing
# Librairie StatModel
import statsmodels
from statsmodels.stats.diagnostic import het_breuschpagan
from statsmodels.tools.tools import add_constant
from statsmodels.discrete.discrete_model import Logit
import statsmodels.api as sm
import statsmodels.formula.api as smf
from scipy.stats import shapiro
from scipy.stats import kstest, norm
# Pour palier aux avertissements à l'utilisation de Seaborn (entre autres)
import warnings
warnings.filterwarnings("ignore")
from P10_Fonctions import *
DF_F = pd.read_csv('billets.csv', sep=';')
infos_DF(DF_F)
# ------------------------------------- Heatmap des valeurs manquantes ------------------------------------
# Remplacer les NaN par True (pour les valeurs manquantes), sinon False
missing_values = DF_F.isnull()
# Heatmap des Nan
Tmessage('Heatmap des valeurs manquantes dans le DataFrame')
plt.figure(figsize=(12, 4))
sns.heatmap(missing_values, cmap='mako', cbar=False)
plt.show()
# ------------------------------------- Création d'une clé primaire ------------------------------------
Tmessage("Création d'une clé primaire")
# Créer une colonne 'ID' avec des identifiants uniques croissants
DF_F['ID'] = range(1, len(DF_F) + 1)
# Afficher le DataFrame avec la nouvelle colonne 'ID'
display(DF_F.head(2))
Text_message("Pour ce projet, une clé primaire n'est pas utile, je la supprime")
DF_F = DF_F.drop(columns='ID', axis=1)
______________________________________________________________________________________________________________________
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|
| 0 | True | 171.81 | 104.86 | 104.95 | 4.52 | 2.89 | 112.83 |
| 1 | True | 171.46 | 103.36 | 103.66 | 3.77 | 2.99 | 113.09 |
| 2 | True | 172.69 | 104.48 | 103.50 | 4.40 | 2.94 | 113.16 |
| Dtype | Non-Null Count | Valeurs unique | moyennes | medianes | ecart_types | min | max | Valeurs manquantes | Valeurs manquantes% | |
|---|---|---|---|---|---|---|---|---|---|---|
| is_genuine | bool | 1500 | 2 | 0.667 | 1.00 | 0.472 | False | True | 0 | 0.00 |
| diagonal | float64 | 1500 | 159 | 171.958 | 171.96 | 0.305 | 171.04 | 173.01 | 0 | 0.00 |
| height_left | float64 | 1500 | 155 | 104.030 | 104.04 | 0.299 | 103.14 | 104.88 | 0 | 0.00 |
| height_right | float64 | 1500 | 170 | 103.920 | 103.92 | 0.326 | 102.82 | 104.95 | 0 | 0.00 |
| margin_low | float64 | 1463 | 285 | 4.486 | 4.31 | 0.664 | 2.98 | 6.9 | 37 | 2.47 |
| margin_up | float64 | 1500 | 123 | 3.151 | 3.14 | 0.232 | 2.27 | 3.91 | 0 | 0.00 |
| length | float64 | 1500 | 336 | 112.678 | 112.96 | 0.873 | 109.49 | 114.44 | 0 | 0.00 |
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length |
|---|
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | ID | |
|---|---|---|---|---|---|---|---|---|
| 0 | True | 171.81 | 104.86 | 104.95 | 4.52 | 2.89 | 112.83 | 1 |
| 1 | True | 171.46 | 103.36 | 103.66 | 3.77 | 2.99 | 113.09 | 2 |
# Distribution des variables
# On créé un Dataset sans les valeurs manquantes
DF_Complet = DF_F.dropna()
for i, column in enumerate(DF_Complet.columns, start=0):
if column != 'is_genuine': # Vérifier si la colonne est différente de 'is_genuine'
# Graphique pour visualiser les outliers
plt.figure(figsize=(12, 3))
plt.subplot(1, 2, 1)
# Visualisation sous forme de graphique
#sns.histplot(DF_F[column], kde=True)
sns.histplot(DF_Complet[column], kde=True, color='teal', edgecolor='black', linewidth=1, line_kws={'color': 'red'})
plt.title(f'Distribution de la colonne {column}', fontsize=14, color='firebrick', fontweight='bold')
# Boîte à moustaches pour détecter les outliers
plt.subplot(1, 2, 2)
# Visualisation sous forme de boxplot
sns.boxplot(x=DF_Complet[column], color='teal',
palette = 'viridis', notch=True, whiskerprops={'linewidth': 1}, showmeans=True,
meanprops=dict(marker='p', markerfacecolor='white', markeredgecolor='black', markersize=8),
medianprops=dict(linestyle='-', linewidth=2, color='firebrick'),
flierprops=dict(marker='p', markerfacecolor='firebrick', markersize=5, markeredgecolor='black'),
boxprops=dict(linestyle='-', linewidth=1.5),
showfliers=True, width=0.4)
plt.title(f'Boxplot de la variable {column}', fontsize=14, color='firebrick', fontweight='bold')
# Affichage valeurs médiane & moyenne:
median_value = np.median(DF_Complet[column])
moy_value = np.mean(DF_Complet[column])
plt.axvline(x=median_value, ymin=0.5, ymax=0, color='firebrick', linestyle=':', linewidth=1)
plt.axvline(x=moy_value, ymin=0.5, ymax=1, color='blue', linestyle=':', linewidth=1)
plt.text(moy_value, -0.3, f'Moyenne: {moy_value:.2f}', color='blue', fontsize=12, ha='left')
plt.text(median_value, 0.4, f'Médiane: {median_value:.2f}', color='firebrick', fontsize=12, ha='right')
plt.tight_layout()
plt.show()
# Calcul de l'IQR
Q1 = DF_F[column].quantile(0.25)
Q3 = DF_F[column].quantile(0.75)
IQR = Q3 - Q1
# Détermination des bornes pour les outliers
seuil_inf = Q1 - 1.5 * IQR
seuil_sup = Q3 + 1.5 * IQR
# Identification des outliers
outliers = DF_Complet[(DF_Complet[column] < seuil_inf) | (DF_Complet[column] > seuil_sup)]
# Affichage des outliers
Text_message('{} : {} Outliers'.format(column, outliers.shape[0]))
Tmessage('---------------------')
# Visualisation des données numériques
Tmessage("Visualisation des relations entre les variables")
sns.set(rc={'axes.facecolor':'black', 'figure.facecolor':'white'})
sns.pairplot(DF_F, hue="is_genuine", palette="viridis")
plt.show()
Text_message("Mise à part 'diagonal', 'Lenght' possède des corrélations +ou- fortes à vérifier avec les autres variables")
Tmessage("-------------------------------------------------------------------------",Color='blue')
message = "Distribution des variables en fonction de 'is_genuine'"
Tmessage(message)
num_cols = len(DF_Complet.columns) - 1
num_rows = num_cols // 5
if num_cols % 5:
num_rows += 1
sns.set(rc={'axes.facecolor':'white', 'figure.facecolor':'white'})
plt.figure(figsize=(10, 4 * num_rows))
for i, column in enumerate(DF_Complet.columns, start=0):
if column != 'is_genuine': # Vérifier si la colonne est différente de 'is_genuine'
plt.subplot(num_rows, 6, i)
sns.boxplot(x='is_genuine', y=column, data=DF_Complet, palette = "viridis", notch=True, showmeans=True,
meanprops=dict(marker='p', markerfacecolor='white', markeredgecolor='black', markersize=8),
medianprops=dict(linestyle='-', linewidth=2, color='orange'),
flierprops=dict(marker='p', markerfacecolor='firebrick', markersize=5, markeredgecolor='black'),
boxprops=dict(linestyle='-', linewidth=1.5), width=0.8)
# Titre du graphique
plt.title(column, y=1,
fontdict={'size': 12, 'weight': 'bold', 'style': 'italic', 'color': 'firebrick'})
plt.ylabel('')
plt.xlabel('')
# Calcul des quantiles
quantiles = np.quantile(DF_Complet.loc[DF_Complet['is_genuine'] == True, column], np.array([0.00, 0.25, 0.5, 0.75, 1]))
# Tracé des lignes horizontales pour les quantiles
for i, q in enumerate(quantiles):
if i == 1 or i == 3: # Sélectionne la deuxième valeur de quantiles
plt.axhline(y=q, color='firebrick', linestyle='-', linewidth=2)
else:
plt.axhline(y=q, color='firebrick', linestyle=':', linewidth=1)
plt.yticks(quantiles, fontsize=8)
plt.tight_layout()
plt.show()
Tmessage("-------------------------------------------------------------------------",Color='blue')
# Calcul pairwise-correlation
#matrix = DF_F.iloc[:,1:].corr(method='pearson')
matrix = DF_F.corr(method='pearson')
# Triangle de corrélations
mask1 = np.tril(np.ones_like(matrix, dtype=bool))
mask2 = np.eye(matrix.shape[0], dtype=bool)
mask = mask1 | mask2
# affichage
message = "Corrélation entre les indicateurs"
Tmessage(message)
plt.figure(figsize=(15, 4))
sns.heatmap(matrix, mask=~mask, annot=True, cmap='viridis')
plt.show()
Pour vérifier 'is_genuine'
'margin_low', 'margin_up' et 'length' sont les plus prédictives
variables = ['diagonal', 'height_left', 'height_right', 'margin_up', 'length']
reg = LinearRegression()
random_seeds = [n for n in range(0,200,1)]
# back to simple regression
X = DF_Complet[variables]
y = DF_Complet['margin_low']
scores = []
for seed in random_seeds:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=seed)
reg.fit(X_train, y_train)
# Prediction sur le test set
y_pred_test = reg.predict(X_test)
scores.append({'seed': seed, 'RMSE': np.round(mean_squared_error(y_test, y_pred_test),4),
'MAPE' : np.round(mean_absolute_percentage_error(y_test, y_pred_test),4),
'R^2' : np.round(reg.score(X_train, y_train), 3)})
scores = pd.DataFrame(scores)
# On conserve la valeur du random_state pour laquelle MAPE est au minimum
Text_message('Valeur du random_state retenue = {}'.format(round(scores.loc[scores['MAPE'].idxmin()]['seed']),0))
random_state = int(round((scores.loc[scores['MAPE'].idxmin()]['seed']),0))
On fixe random_state à 61
Cette valeur n'est valable que dans le cadre de notre dataset
# Remplacement du bool par 0 ou 1
DF_F["is_genuine"].replace([True, False], [1,0], inplace=True)
# On créé un Dataset avec les individus qui ont un marhin_low = NaN
DF_NaN = DF_F.loc[DF_F["margin_low"].isna()]
# On créé un Dataset sans les valeurs manquantes
DF_Complet = DF_F.dropna()
régression linéaire simplet
Prenons la variable la plus corrélée 'Length' avec 'margin_low'
DF_RLS = DF_Complet.copy()
# Choisissez vos variables indépendantes et dépendantes
X = DF_RLS["length"] # Choisissez vos variables indépendantes
y = DF_RLS["margin_low"] # Variable dépendante (continue)
# Ajoutez une colonne constante à X pour l'intercept
X_with_const = sm.add_constant(X)
# Divisez vos données en ensembles d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(X_with_const, y, test_size=0.2, random_state=random_state)
# Créez le modèle de régression linéaire
model = sm.OLS(y_train, X_train)
# Ajustez le modèle aux données
result = model.fit()
# Affichez les résultats
print(result.summary())
# Faites des prédictions sur les données de test
y_pred = result.predict(X_test)
# Calcul du RMSE
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
# Calcul du MAE
mae = mean_absolute_error(y_test, y_pred)
# Calcul du MAPE
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
# Affichage des résultats
Text_message("RMSE: {}".format(rmse.round(4)))
Text_message("MAE: {}".format( mae.round(4)))
Text_message("MAPE: {} %".format(mape.round(4)))
OLS Regression Results
==============================================================================
Dep. Variable: margin_low R-squared: 0.440
Model: OLS Adj. R-squared: 0.439
Method: Least Squares F-statistic: 916.1
Date: Thu, 25 Jul 2024 Prob (F-statistic): 4.83e-149
Time: 19:50:22 Log-Likelihood: -855.58
No. Observations: 1170 AIC: 1715.
Df Residuals: 1168 BIC: 1725.
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 61.3339 1.878 32.652 0.000 57.648 65.019
length -0.5046 0.017 -30.267 0.000 -0.537 -0.472
==============================================================================
Omnibus: 64.168 Durbin-Watson: 1.970
Prob(Omnibus): 0.000 Jarque-Bera (JB): 82.522
Skew: 0.514 Prob(JB): 1.20e-18
Kurtosis: 3.799 Cond. No. 1.44e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.44e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
régression linéaire multiple
# Choisissez vos variables indépendantes et dépendantes
X = DF_Complet.drop(["is_genuine", "margin_low"], axis=1) # Choisissez vos variables indépendantes
y = DF_Complet["margin_low"] # Variable dépendante (continue)
# Ajoutez une colonne constante à X pour l'intercept
X_with_const = sm.add_constant(X)
# Divisez vos données en ensembles d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(X_with_const, y, test_size=0.2, random_state=random_state)
# Créez le modèle de régression linéaire
model = sm.OLS(y_train, X_train)
# Ajustez le modèle aux données
result = model.fit()
# Affichez les résultats
print(result.summary())
# Faites des prédictions sur les données de test
y_pred = result.predict(X_test)
# Calcul du RMSE
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
# Calcul du MAE
mae = mean_absolute_error(y_test, y_pred)
# Calcul du MAPE
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
# Affichage des résultats
Text_message("RMSE: {}".format(rmse.round(4)))
Text_message("MAE: {}".format( mae.round(4)))
Text_message("MAPE: {} %".format(mape.round(4)))
OLS Regression Results
==============================================================================
Dep. Variable: margin_low R-squared: 0.471
Model: OLS Adj. R-squared: 0.469
Method: Least Squares F-statistic: 207.7
Date: Thu, 25 Jul 2024 Prob (F-statistic): 2.36e-158
Time: 19:50:25 Log-Likelihood: -821.31
No. Observations: 1170 AIC: 1655.
Df Residuals: 1164 BIC: 1685.
Df Model: 5
Covariance Type: nonrobust
================================================================================
coef std err t P>|t| [0.025 0.975]
--------------------------------------------------------------------------------
const 22.1433 10.994 2.014 0.044 0.572 43.714
diagonal -0.1017 0.046 -2.191 0.029 -0.193 -0.011
height_left 0.1702 0.051 3.322 0.001 0.070 0.271
height_right 0.2593 0.049 5.338 0.000 0.164 0.355
margin_up 0.2827 0.074 3.828 0.000 0.138 0.428
length -0.4058 0.020 -19.857 0.000 -0.446 -0.366
==============================================================================
Omnibus: 43.110 Durbin-Watson: 1.984
Prob(Omnibus): 0.000 Jarque-Bera (JB): 50.661
Skew: 0.420 Prob(JB): 9.98e-12
Kurtosis: 3.577 Cond. No. 1.94e+05
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.94e+05. This might indicate that there are
strong multicollinearity or other numerical problems.
Suppression des variables 'diagonal' et 'height_left'¶
# Choisissez vos variables indépendantes et dépendantes
X = DF_Complet.drop(["is_genuine", "margin_low", "diagonal", "height_left"], axis=1) # Choisissez vos variables indépendantes
y = DF_Complet["margin_low"] # Variable dépendante (continue)
# Ajoutez une colonne constante à X pour l'intercept
X_with_const = sm.add_constant(X)
# Divisez vos données en ensembles d'entraînement et de test
X_train, X_test, y_train, y_test = train_test_split(X_with_const, y, test_size=0.2, random_state=random_state)
# Créez le modèle de régression linéaire
model = sm.OLS(y_train, X_train)
# Ajustez le modèle aux données
result = model.fit()
# Affichez les résultats
print(result.summary())
# Faites des prédictions sur les données de test
y_pred = result.predict(X_test)
# Calcul du RMSE
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
# Calcul du MAE
mae = mean_absolute_error(y_test, y_pred)
# Calcul du MAPE
mape = np.mean(np.abs((y_test - y_pred) / y_test)) * 100
# Affichage des résultats
Text_message("RMSE: {}".format(rmse.round(4)))
Text_message("MAE: {}".format( mae.round(4)))
Text_message("MAPE: {} %".format(mape.round(4)))
OLS Regression Results
==============================================================================
Dep. Variable: margin_low R-squared: 0.464
Model: OLS Adj. R-squared: 0.463
Method: Least Squares F-statistic: 337.1
Date: Thu, 25 Jul 2024 Prob (F-statistic): 1.38e-157
Time: 19:50:26 Log-Likelihood: -828.97
No. Observations: 1170 AIC: 1666.
Df Residuals: 1166 BIC: 1686.
Df Model: 3
Covariance Type: nonrobust
================================================================================
coef std err t P>|t| [0.025 0.975]
--------------------------------------------------------------------------------
const 22.8377 6.157 3.709 0.000 10.758 34.917
height_right 0.2718 0.049 5.590 0.000 0.176 0.367
margin_up 0.3075 0.074 4.155 0.000 0.162 0.453
length -0.4222 0.020 -20.999 0.000 -0.462 -0.383
==============================================================================
Omnibus: 49.349 Durbin-Watson: 1.978
Prob(Omnibus): 0.000 Jarque-Bera (JB): 59.018
Skew: 0.454 Prob(JB): 1.53e-13
Kurtosis: 3.622 Cond. No. 6.56e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 6.56e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
# Créez un graphique de dispersion des valeurs observées vs prédites
plt.figure(figsize=(12,3))
Tmessage("Régression Linéaire - Valeurs Observées vs Prédites (Set de Tests)")
sns.scatterplot(x=y_test, y=y_pred, color='teal', alpha=0.5)
sns.lineplot(x=y_test, y=y_test, color='red', label="Droite de Régression Linéaire")
plt.xlabel("Valeurs Observées")
plt.ylabel("Valeurs Prédites")
plt.show()
Colinéarité des variables
# Calcul des VIF pour chaque variable indépendante
vif_data = pd.DataFrame()
vif_data["Variable"] = X_with_const.columns
vif_data["VIF"] = [variance_inflation_factor(X_with_const.values, i) for i in range(X_with_const.shape[1])]
# Affichage des résultats
vif_data = vif_data.drop(index=0).reset_index(drop=True)
display(vif_data)
Tmessage("Coefficients inférieurs à 10 (Avec Intercept et Sans Intercept(data scalées))",
Color='black', Align='left', Size='12')
Tmessage("Il n'y a donc pas de problème de colinéarité", Color='firebrick', Align='left', Size='12')
| Variable | VIF | |
|---|---|---|
| 0 | height_right | 1.213794 |
| 1 | margin_up | 1.394010 |
| 2 | length | 1.509435 |
VIF = 1 : Aucune colinéarité. Les variables indépendantes ne sont pas corrélées les unes avec les autres.
1 < VIF < 5 : Colineárité modérée. Bien que certaine colinéarité puisse être présente, elle est généralement considérée comme acceptable dans cette plage.
VIF ≥ 5 : Colineárité élevée. Les variables indépendantes sont fortement corrélées, ce qui peut entraîner une instabilité dans les estimations des coefficients.
VIF ≥ 10 : Colineárité très élevée. Ceci indique une forte colinéarité, et il est généralement recommandé de prendre des mesures correctives, telles que l'exclusion de certaines variables.
Homoscédasticité
from statsmodels.stats.diagnostic import het_breuschpagan
# Test de Breusch-Pagan
test_result_bp = het_breuschpagan(result.resid, X_train)
Tmessage("Test de Breusch-Pagan:")
print("Statistique de test:", test_result_bp[0])
print("p-valeur:", test_result_bp[1])
print("L'effet de l'hétéroscédasticité est-il significatif ?", test_result_bp[1] < 0.05)
Tmessage("la variance des résidus n'est pas constante", Align='left', Color = 'blue')
# Calculer les résidus standardisés
residuals = result.resid
# Créer un graphique de dispersion
plt.figure(figsize=(10, 4))
Tmessage("Homoscédasticité : Dispersion des Résidus")
sns.scatterplot(x=X_train.index, y=residuals, color='teal', alpha=0.7)
plt.ylabel("Résidus")
plt.axhline(0, color='red', linestyle='--', linewidth=2, label='Ligne Zéro')
# Ajouter un peu de style avec une ligne en pointillé rouge représentant la ligne zéro
plt.legend()
plt.show()
Statistique de test: 68.51546882848272 p-valeur: 8.873495179862817e-15 L'effet de l'hétéroscédasticité est-il significatif ? True
Statistique de test :
La statistique de test, généralement notée chi-carré (χ²), mesure à quel point les erreurs de variance sont homogènes. Plus la statistique de test est élevée, plus l'hétéroscédasticité est probable.
la p-valeur est < 0.05 :
Il y a des preuves significatives d'hétéroscédasticité dans les résidus du modèle. Nous devrions envisager des approches pour corriger l'hétéroscédasticité, telles que l'utilisation de méthodes de régression robustes.
Normalité des résidus
# Calculer les résidus
residuals = y_test - y_pred
plt.figure(figsize=(12,3))
Tmessage("Histogramme des résidus")
sns.distplot(residuals, bins='auto', color = 'teal')
plt.xlabel('Résidus')
plt.ylabel('Fréquence')
plt.show()
plt.figure(figsize=(12,3))
Tmessage("Graphique quantile-quantile des résidus")
# Tracer le graphique quantile-quantile (Q-Q plot)
stats.probplot(residuals, dist="norm", plot=plt)
plt.xlabel("Quantiles théoriques")
plt.ylabel("Quantiles observés")
plt.show()
# Test de Shapiro-Wilk:
Tmessage("Test de Shapiro-Wilk", Color='teal',Size= 14)
stat, p_value = shapiro(result.resid)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
if p_value > 0.05:
Tmessage("Les résidus suivent une distribution normale.", Align='left', Color='firebrick',Size= 12)
else:
Tmessage("Les résidus ne suivent pas une distribution normale.", Align='left', Color='firebrick',Size= 12)
# Test de Kolmogorov-Smirnov:
Tmessage("Test de Kolmogorov-Smirnov", Color='teal',Size= 14)
stat, p_value = kstest(result.resid, norm.cdf)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
if p_value > 0.05:
Tmessage("Les résidus suivent une distribution normale.", Align='left', Color='firebrick',Size= 12)
else:
Tmessage("Les résidus ne suivent pas une distribution normale.", Align='left', Color='firebrick',Size= 12)
from sklearn.preprocessing import MinMaxScaler
from sklearn import preprocessing
from sklearn.preprocessing import PowerTransformer
from sklearn.preprocessing import Normalizer
regressions = {
'margin_low ~ diagonal + height_left + height_right + margin_up + length'
: ['diagonal','height_left', 'height_right', 'margin_up', 'length']}
# boucle sur les régressions
for title, variables in regressions.items():
Tmessage('----------- Choix du pré-traitement sur :--------------',Color='blue')
Tmessage(title)
# Instancier et appliquer le Scaler
scal = [Normalizer(), PowerTransformer(method='yeo-johnson'), preprocessing.StandardScaler(), MinMaxScaler(),
'Transformation logarithmique', 'Sans traitement']
for scl in scal:
if scl == 'Transformation logarithmique':
DF_clean = DF_Complet.mask(DF_Complet[variables] <= 0, 0.1)
data_array = np.log1p(DF_clean)
# Conversion en dataframe
df_scaled = pd.DataFrame(data_array, columns = variables)
elif scl == 'Sans traitement':
df_scaled = DF_Complet.copy()
else:
scaler = scl
data_array = scaler.fit_transform(DF_Complet[variables])
# Conversion en dataframe
df_scaled = pd.DataFrame(data_array, columns = variables)
# Affichage du prétraitement:
message = f' {scl}'
Tmessage(message, Color='blue', Align='left', Style='none', Size='12', Police='arial')
# les variables prédictives
X = df_scaled[variables]
# la variable cible, le poids
y = DF_Complet['margin_low']
# Train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=random_state)
# entrainer le modele
reg = LinearRegression()
reg.fit(X_train, y_train)
# Prediction sur le test set
y_pred_test = reg.predict(X_test)
# Scores
a = np.round(reg.score(X_train, y_train), 3)
b = np.round(mean_squared_error(y_test, y_pred_test),4)
c = np.round(mean_absolute_error(y_test, y_pred_test),4)
d = np.round(mean_absolute_percentage_error(y_test, y_pred_test),4)
Text_message("R^2 : {} --- RMSE: {} --- MAE : {} --- MAPE: {}".format(a,b,c,d))
Aucun pré-traitement ne sort du lot
On conserve le DF sans traitement
regressions = {
'margin_low ~ diagonal + height_left + height_right + margin_up + length': ['diagonal','height_left', 'height_right', 'margin_up', 'length'],
'margin_low ~ height_left + height_right + margin_up + length': ['height_left', 'height_right', 'margin_up', 'length'],
'margin_low ~ height_right + margin_up + length': ['height_right', 'margin_up', 'length'],
'margin_low ~ margin_up + length': ['margin_up', 'length'], 'margin_low ~ length': ['length']
}
reg = LinearRegression()
# boucle sur les régressions
for title, variables in regressions.items():
# les variables prédictives
scaler = preprocessing.StandardScaler()
data_array = scaler.fit_transform(DF_Complet[variables])
df_scaled = pd.DataFrame(data_array, columns = variables)
X = DF_Complet[variables]
# la variable cible, le poids
y = DF_Complet.margin_low
# Train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=random_state)
# entrainer le modele
reg.fit(X_train, y_train)
# Prediction sur le test set
y_pred_test = reg.predict(X_test)
# Scores
Tmessage("---------------------------Variables prédictives pour 'margin_low' -----------------------",Color='blue')
Tmessage(title)
a = np.round(reg.score(X_train, y_train), 3)
b = np.round(mean_squared_error(y_test, y_pred_test),4)
c = np.round(mean_absolute_error(y_test, y_pred_test),4)
d = np.round(mean_absolute_percentage_error(y_test, y_pred_test),5)
Text_message("R^2 : {} --- RMSE: {} --- MAE : {} --- MAPE: {} %".format(a,b,c,d*100))
mape = (1 / len(y_test)) * sum(abs((y_test - y_pred_test) / y_test) * 100)
#print("MAPE:", mape)
margin_low ~ 'toutes variables' a le MAPE le plus bas
Nous avons vu que 'diagonal' et 'height_left' ne sont que peu prédictives
----
margin_low ~ height_right + margin_up + length est validé avec MAPE = 7.115 %
regressions = {'margin_low ~ height_right + margin_up + length': ['height_right', 'margin_up', 'length']}
reg = LinearRegression()
# boucle sur les régressions
for title, variables in regressions.items():
# les variables prédictives
X = DF_Complet[variables]
# la variable cible, le poids
y = DF_Complet.margin_low
# Train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=random_state)
# entrainer le modele
reg.fit(X_train, y_train)
# Prediction sur le test set
y_pred_test = reg.predict(X_test)
# Scores
Tmessage("--------------------------- Variables prédictives ------------------------",Color='blue')
Tmessage(title)
a = np.round(reg.score(X_train, y_train), 3)
b = np.round(mean_squared_error(y_test, y_pred_test),4)
c = np.round(mean_absolute_error(y_test, y_pred_test),4)
d = np.round(mean_absolute_percentage_error(y_test, y_pred_test),4)
Text_message("R^2 : {} --- RMSE: {} --- MAE : {} --- MAPE: {}".format(a,b,c,d))
# Créez un DataFrame contenant les caractéristiques pour prédiction
data_to_predict = X_test
# Utilisez le modèle pour prédire les valeurs pour les données manquantes dans 'margin_low'
prediction_array = reg.predict(data_to_predict)
merged_df = pd.merge(X_test, y_test, left_index=True, right_index=True)
# Remplacez les valeurs NaN dans 'margin_low' par les valeurs prédites
merged_df['margin_low_Predict'] = prediction_array
merged_df['% erreur'] = round(abs(100 - (merged_df['margin_low_Predict']*100 / merged_df['margin_low'])),2)
# Affichage
Color='blue'
Align='left'
Style='none'
Size='12'
Police='arial'
Tmessage("Vérification des résultats sur l'échantillon Test",Color, Align, Style, Size)
display(merged_df.head(3))
Text_message("Vérification erreur moyenne : {} %".format(merged_df['% erreur'].mean().round(3)))
# Créez un DataFrame contenant les caractéristiques pour prédiction
data_to_predict = DF_NaN[variables]
# Utilisez le modèle pour prédire les valeurs pour les données manquantes dans 'margin_low'
prediction_array = reg.predict(data_to_predict)
# Remplacez les valeurs NaN dans 'margin_low' par les valeurs prédites
DF_NaN['margin_low'] = prediction_array.round(3)
# Affichage
Color='blue'
Align='left'
Style='none'
Size='12'
Police='arial'
Tmessage("Imputation des 'margin-low' dans le DF_NaN",Color, Align, Style, Size)
display(DF_NaN.head(3))
# ________________________________________ Graphique _____________________________
Tmessage("--------------------------- Graphiques d'interprétation ------------------------",Color='blue')
DFC = DF_Complet.copy()
DFN = DF_NaN.copy()
# Création de la figure et des sous-graphiques
fig, axs = plt.subplots(1, 3, figsize=(12, 4))
# Tracé des graphiques dans chaque sous-graphique
plot_regression(DFC, DFN, 'length', "'margin-low' en fonction de 'length'", axs[0])
plot_regression(DFC, DFN, 'height_right', "'margin-low' en fonction de 'height_right'", axs[1])
plot_regression(DFC, DFN, 'margin_up', "'margin-low' en fonction de 'margin_up'", axs[2])
# Rétablir les valeurs originales pour éviter les modifications permanentes dans les DataFrames
DFC['is_genuine'] = DFC['is_genuine'].replace({'Faux': 0, 'Vrai': 1})
DFN['is_genuine'] = DFN['is_genuine'].replace({'Faux': 0, 'Vrai': 1})
# Récupérer les positions des axes
pos1 = axs[0].get_position()
pos2 = axs[1].get_position()
# Créer une légende commune
fig.legend(labels=['DF_Complet','Faux billets', 'Vrais billets', 'Régression linéaire',
'Interval de confiance', 'DF_NaN', 'Prédict Vrais billets', 'Prédict Faux billets'],
loc='upper center', bbox_to_anchor=((pos1.x0 + pos2.x1) / 1.5, pos1.y1-0.9), ncol=4)
plt.show()
| height_right | margin_up | length | margin_low | margin_low_Predict | % erreur | |
|---|---|---|---|---|---|---|
| 1301 | 104.19 | 3.25 | 111.99 | 5.72 | 4.867881 | 14.90 |
| 1028 | 103.93 | 3.49 | 111.34 | 5.38 | 5.145473 | 4.36 |
| 281 | 104.21 | 3.07 | 113.01 | 4.18 | 4.387276 | 4.96 |
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|
| 72 | 1 | 171.94 | 103.89 | 103.45 | 4.329 | 3.25 | 112.79 |
| 99 | 1 | 171.93 | 104.07 | 104.18 | 4.371 | 3.14 | 113.08 |
| 151 | 1 | 172.07 | 103.80 | 104.38 | 4.452 | 3.02 | 112.93 |
Création du modèle de régression avec Statsmodels: forcer l'intercept à zéro peut être pertinent.¶
Théoriquement, la droite de régression passe par l'origine du graphique (0,0).¶
Dans notre cas, on suppose que lorsque toutes les variables indépendantes (prédictives) sont nulles, la variable dépendante (margin_low) est également nulle.¶
df =DF_Complet.copy()
test_size = 0.2
# Séparer les données en ensemble d'entraînement et ensemble de test
train_df, test_df = train_test_split(df, test_size=test_size, random_state=random_state)
# Création du modèle de régression linéaire
model = smf.ols(formula='margin_low ~ height_right + margin_up + length', data=train_df)
# Ajuster le modèle aux données d'entraînement
results_AvecIntercept = model.fit()
# Effectuer des prédictions sur l'ensemble de test
predictions_AvecIntercept = results_AvecIntercept.predict(X_test)
# Calculer MAE
mae = mean_absolute_error(y_test, predictions_AvecIntercept)
# Calculer RMSE
rmse = np.sqrt(mean_squared_error(y_test, predictions_AvecIntercept))
# Calculer MAPE
def mean_absolute_percentage_error(y_true, y_pred):
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
mape = mean_absolute_percentage_error(y_test, predictions_AvecIntercept)
# Calculer le coefficient de détermination (R²)
r_squared = r2_score(y_test, predictions_AvecIntercept)
Tmessage('Résultats avec intercept', Align='left')
Text_message(f"R-squared (R²): {r_squared:.4f}")
Text_message(f"MAE: {mae:.5f}")
Text_message(f"RMSE: {rmse:.5f}")
Text_message(f"MAPE: {mape:.5f}%")
df =DF_Complet.copy()
# Séparation des données
train_df, test_df = train_test_split(df, test_size=test_size, random_state=random_state)
# Création du modèle de régression linéaire
model = smf.ols(formula='margin_low ~ height_right + margin_up + length - 1', data=train_df)
# On fit
results_SansIntercept = model.fit()
# Prédictions sur Test
predictions_SansIntercept = results_SansIntercept.predict(X_test)
# Affichage
#display(results.summary())
# Calculer MAE
mae = mean_absolute_error(y_test, predictions_SansIntercept)
# Calculer RMSE
rmse = np.sqrt(mean_squared_error(y_test, predictions_SansIntercept))
# Calculer MAPE
def mean_absolute_percentage_error(y_true, y_pred):
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
mape = mean_absolute_percentage_error(y_test, predictions_SansIntercept)
# Calcule du coef de détermination (R²)
r_squared = r2_score(y_test, predictions_SansIntercept)
Tmessage('Résultats sans intercept', Align='left')
Text_message(f"R-squared (R²): {r_squared:.4f}")
Text_message(f"MAE: {mae:.5f}")
Text_message(f"RMSE: {rmse:.5f}")
Text_message(f"MAPE: {mape:.5f}%")
AIC (Akaike Information Criterion) & BIC (Bayesian Information Criterion)
# Calcul de l'AIC et du BIC Avec Intercept
aic = round(results_AvecIntercept.aic,3)
bic = round(results_AvecIntercept.bic,3)
Tmessage("Avec Intercept:",Align='left')
Tmessage("AIC : {} / BIC : {}".format(aic,bic),Color ='teal', Align='left', Style='italic', Size='12', Police='arial')
# Calcul de l'AIC et du BIC Sans Intercept
aic = round(results_SansIntercept.aic,3)
bic = round(results_SansIntercept.bic,3)
Tmessage("Sans Intercept:",Align='left', Style='italic', Size='14', Police='arial')
Tmessage("AIC : {} / BIC : {}".format(aic,bic),Color ='teal', Align='left', Style='italic', Size='12', Police='arial')
Tmessage("Les différences entre les modèles ne sont pas suffisantes pour déterminer le meilleur compromis entre ajustement et complexité",
Color ='blue', Align='center', Style='italic', Size='12', Police='arial')
Indépendance des erreurs
# Récupération des valeurs prédites et des résidus sans intercept
predicted_values = results_SansIntercept.fittedvalues
residuals = results_SansIntercept.resid
# Récupération des valeurs prédites et des résidus avec intercept
predicted_values1 = results_AvecIntercept.fittedvalues
residuals1 = results_AvecIntercept.resid
# Création d'un DataFrame pour le graphique des résidus
residuals_df = pd.DataFrame({'Valeurs prédites': predicted_values, 'Résidus': residuals})
residuals_df1 = pd.DataFrame({'Valeurs prédites': predicted_values1, 'Résidus': residuals1})
# Tracé du graphique des résidus
sns.set(rc={'axes.facecolor': 'white', 'figure.facecolor': 'white'})
plt.figure(figsize=(12,4))
sns.residplot(data=residuals_df, x='Valeurs prédites', y='Résidus', color='teal', scatter_kws={'alpha': 0.8}, lowess=True,
line_kws={'color': 'firebrick', 'linewidth': 6})
sns.residplot(data=residuals_df1, x='Valeurs prédites', y='Résidus', color='orange', scatter_kws={'alpha': 0.5}, lowess=True,
line_kws={'color': 'blue', 'linewidth': 2})
plt.xlabel('Valeurs prédites')
plt.ylabel('Résidus')
plt.title('Graphique des résidus pour une régression linéaire multiple', y=1,
fontdict={'size': 12, 'weight': 'bold', 'style': 'italic', 'color': 'firebrick'})
# Ajout de légendes factices pour le graphique
plt.scatter([], [], color='teal', label='Sans intercept') # Élément pour les points dispersés
plt.plot([], [], color='firebrick', linewidth=2, label='Régression lissée') # Élément pour la ligne de régression lissée
plt.scatter([], [], color='orange', label='Avec intercept') # Élément pour les points dispersés
plt.plot([], [], color='blue', linewidth=2, label='Régression lissée') # Élément pour la ligne de régression lissée
# Afficher la légende
plt.legend(loc='best') # Modifier la position de la légende selon vos besoins
plt.show()
# Conclusion:
Tmessage("Pas de différences notables entre les deux modèles", Color='blue', Align='center', Size='14')
Vérifier la colinéarité des variables
# Avec Intercept
Text_message("Facteur d'inflation de la variance avec Intercept")
varAI = results_AvecIntercept.model.exog
vif_AI = pd.DataFrame()
vif_AI["Variables"] = X_train.columns
vif_AI["VIF"] = [variance_inflation_factor(varAI, i) for i in np.arange(1,varAI.shape[1])]
display(vif_AI)
Tmessage("Coefficients inférieurs à 10 (Avec Intercept et Sans Intercept(data scalées))",
Color='black', Align='left', Size='10')
Tmessage("Il n'y a donc pas de problème de colinéarité", Color='black', Align='left', Size='10')
# Sans Intercept
Text_message("Facteur d'inflation de la variance sans Intercept")
varSI = results_SansIntercept.model.exog
vif_SI = pd.DataFrame()
vif_SI["Variables"] = X_train.columns
vif_SI["VIF"] = [variance_inflation_factor(varSI, i) for i in np.arange(0,varSI.shape[1])]
display(vif_SI)
Tmessage("On scale les données pour minimiser les différences de tailles des variables",
Color='black', Align='left', Size='10')
df =DF_Complet.copy()
scaler = preprocessing.StandardScaler()
data_array = scaler.fit_transform(df[['margin_low','height_right', 'margin_up', 'length']])
df = pd.DataFrame(data_array, columns = ['margin_low','height_right', 'margin_up', 'length'])
variables=['height_left', 'height_right', 'margin_up', 'length']
# Séparation des données
train_df, test_df = train_test_split(df, test_size=0.2, random_state=random_state)
# Création du modèle de régression linéaire
model = smf.ols(formula='margin_low ~ height_right + margin_up + length -1', data=train_df)
# On fit
resultsSansIntercept = model.fit()
Text_message("Facteur d'inflation de la variance sans Intercept (data scalées)")
varSIscaled = resultsSansIntercept.model.exog
vif_SI = pd.DataFrame()
vif_SI["Variables"] = X_train.columns
vif_SI["VIF"] = [variance_inflation_factor(varSIscaled, i) for i in np.arange(0,varSIscaled.shape[1])]
display(vif_SI)
Tmessage("Coefficients inférieurs à 10 (Avec Intercept et Sans Intercept(data scalées))",
Color='black', Align='left', Size='10')
Tmessage("Il n'y a donc pas de problème de colinéarité", Color='black', Align='left', Size='10')
Tmessage("Pour les deux modèles, pas de problème de colinéarité", Color='blue', Align='center', Size='14')
| Variables | VIF | |
|---|---|---|
| 0 | height_right | 1.207999 |
| 1 | margin_up | 1.396446 |
| 2 | length | 1.519821 |
| Variables | VIF | |
|---|---|---|
| 0 | height_right | 17037.112090 |
| 1 | margin_up | 261.096721 |
| 2 | length | 14793.687996 |
| Variables | VIF | |
|---|---|---|
| 0 | height_right | 1.208128 |
| 1 | margin_up | 1.396593 |
| 2 | length | 1.519928 |
Tester l’homoscédasticité
NB : tester l’homoscédasticité, c'est tester la constance de la variance des résidus¶
from statsmodels.stats.diagnostic import het_breuschpagan
varSI = sm.add_constant(varSI)
varSI= pd.DataFrame(varSI)
# Test de Breusch-Pagan
test_result_bp = statsmodels.stats.diagnostic.het_breuschpagan(results_SansIntercept.resid, varSI)
Tmessage("Test de Breusch-Pagan:")
print("Statistique de test:", test_result_bp[0])
print("p-valeur:", test_result_bp[1])
print("L'effet de l'hétéroscédasticité est-il significatif ?", test_result_bp[1] < 0.05)
Tmessage("la variance des résidus n'est pas constante", Align='left', Color = 'blue')
# Calculer les résidus standardisés
residuals1 = results_SansIntercept.resid
# Créer un graphique de dispersion
plt.figure(figsize=(10, 4))
Tmessage("Homoscédasticité : Dispersion des Résidus 'Sans intercept'")
sns.scatterplot(x=varSI.index, y=residuals1, color='teal', alpha=0.7)
plt.ylabel("Résidus")
plt.axhline(0, color='red', linestyle='--', linewidth=2, label='Ligne Zéro') # Ajouter la ligne zéro
plt.legend()
plt.show()
Tmessage("p-valeur < à 5% pour les deux modèles - hypothèse 𝐻0 rejetée selon laquelle les variances sont constantes / hypothèse d’homoscédasticité",
Color='blue')
Tmessage("------------------------------------------------------------------------------------------", Color='black')
# Test de Breusch-Pagan
test_result_bp = statsmodels.stats.diagnostic.het_breuschpagan(results_AvecIntercept.resid, varSI)
Tmessage("Test de Breusch-Pagan:")
print("Statistique de test:", test_result_bp[0])
print("p-valeur:", test_result_bp[1])
print("L'effet de l'hétéroscédasticité est-il significatif ?", test_result_bp[1] < 0.05)
Tmessage("la variance des résidus n'est pas constante", Align='left', Color = 'blue')
# Calculer les résidus standardisés
residuals = results_AvecIntercept.resid
# Créer un graphique de dispersion
plt.figure(figsize=(10, 4))
Tmessage("Homoscédasticité : Dispersion des Résidus 'Avec intercept'")
sns.scatterplot(x=varSI.index, y=residuals, color='teal', alpha=0.7)
plt.ylabel("Résidus")
plt.axhline(0, color='red', linestyle='--', linewidth=2, label='Ligne Zéro') # Ajouter la ligne zéro
plt.legend()
plt.show()
Tmessage("p-valeur < à 5% pour les deux modèles - hypothèse 𝐻0 rejetée selon laquelle les variances sont constantes / hypothèse d’homoscédasticité",
Color='blue')
Tmessage("------------------------------------------------------------------------------------------", Color='black')
plt.figure(figsize=(10, 4))
Tmessage("Homoscédasticité : Dispersion des Résidus - Comparaison")
sns.scatterplot(x=varSI.index, y=residuals, color='teal', alpha=0.7, label="Avec intercept")
sns.scatterplot(x=varSI.index, y=residuals1, color='firebrick', alpha=0.7, label="Sans intercept")
plt.ylabel("Résidus")
plt.axhline(0, color='red', linestyle='--', linewidth=2, label='Ligne Zéro') # Ajouter la ligne zéro
plt.legend()
plt.show()
Statistique de test: 65.51362629168382 p-valeur: 3.894809736584079e-14 L'effet de l'hétéroscédasticité est-il significatif ? True
Statistique de test: 68.51546882848272 p-valeur: 8.873495179862817e-15 L'effet de l'hétéroscédasticité est-il significatif ? True
Tester la normalité des résidus
Si l'on veut tester la normalité des résidus, on peut faire un test de Shapiro-Wilk¶
Tmessage("Normalité des résidus", Size=18)
# Test de Shapiro-Wilk:
Tmessage("Test de Shapiro-Wilk", Color='Blue',Size= 14)
Text_message("Modèle avec intercept")
stat, p_value = shapiro(results_AvecIntercept.resid)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
Text_message("Modèle sans intercept")
stat, p_value = shapiro(results_SansIntercept.resid)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
# Test de Kolmogorov-Smirnov:
Tmessage("Test de Kolmogorov-Smirnov", Color='Blue',Size= 14)
Text_message("Modèle avec intercept")
stat, p_value = kstest(results_AvecIntercept.resid, norm.cdf)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
Text_message("Modèle sans intercept")
stat, p_value = kstest(results_SansIntercept.resid, norm.cdf)
Tmessage("Statistic: {}".format(stat), Align='left', Color='Black',Size= 12)
Tmessage("p-value: {}".format(p_value), Align='left', Color='Black',Size= 12)
fig, axes = plt.subplots(1, 2, figsize=(10, 3)) # 1 ligne, 2 colonnes
# Tracé du premier graphique
sns.distplot(results_SansIntercept.resid, ax=axes[1])
axes[1].set_title('Résidus sans intercept',color='firebrick')
# Tracé du deuxième graphique
sns.distplot(results_AvecIntercept.resid, ax=axes[0])
axes[0].set_title('Résidus avec intercept',color='firebrick')
# Ajustement de l'espacement entre les sous-graphiques
plt.tight_layout()
# Affichage des graphiques côte à côte
plt.show()
# Calcul des résidus sans intercept
resSansIntercept = results_SansIntercept.resid
# Calcul des résidus avec intercept
resAvecIntercept = results_AvecIntercept.resid
sns.set(rc={'axes.facecolor': 'white', 'figure.facecolor': 'white'})
fig, axes = plt.subplots(1, 2, figsize=(12, 4)) # Créer une grille de sous-graphiques : 1 ligne, 2 colonnes
# Premier Q-Q plot pour les résidus sans intercept
sm.qqplot(resSansIntercept, line='s', label="Résidus Sans Intercept", ax=axes[1])
axes[1].set_title("Hypothèse de la normalité des résidus : Q-Q plot (Sans Intercept)",color='firebrick')
axes[1].legend()
# Deuxième Q-Q plot pour les résidus avec intercept
sm.qqplot(resAvecIntercept, line='s', label="Résidus Avec Intercept", ax=axes[0])
axes[0].set_title("Hypothèse de la normalité des résidus : Q-Q plot (Avec Intercept)",color='firebrick')
axes[0].legend()
plt.tight_layout() # Ajuster la disposition pour éviter les chevauchements
plt.show()
Tmessage("Les résidus ne suivent pas une distribution normale.", Color='firebrick',Size= 16)
# Création d'un Dataset avec les individus qui ont un marhin_low = NaN
DF_NaN = DF_F.loc[DF_F["margin_low"].isna()]
# Création d'un Dataset sans les valeurs manquantes
DF_Complet = DF_F.dropna()
# On créé un Dataset sans les valeurs manquantes
df =DF_Complet.copy()
# Séparation des données
train_df, test_df = train_test_split(df, test_size=0.2, random_state=random_state)
# Split Train
X_train = train_df[['height_right', 'margin_up', 'length']]
y_train = train_df['margin_low']
# Spli Test
X_test = test_df[['height_right', 'margin_up', 'length']]
y_test = test_df['margin_low']
Tmessage("Modèle sans Intercept")
# Création du modèle de régression linéaire
model = smf.ols(formula='margin_low ~ height_right + margin_up + length - 1', data=train_df)
# On fit
results_SansIntercept = model.fit()
# Prédictions sur Test
predictions_SansIntercept = results_SansIntercept.predict(X_test)
# Créez un DataFrame contenant les caractéristiques pour prédiction
data_to_predict = X_test
# Utilisez le modèle pour prédire les valeurs pour les données manquantes dans 'margin_low'
prediction_array = results_SansIntercept.predict(data_to_predict)
merged_df = pd.merge(X_test, y_test, left_index=True, right_index=True)
# Remplacez les valeurs NaN dans 'margin_low' par les valeurs prédites
merged_df['margin_low_Predict'] = prediction_array
merged_df['% erreur'] = round(abs(100 - (merged_df['margin_low_Predict']*100 / merged_df['margin_low'])),2)
display(merged_df.head())
r_squared = round(r2_score(y_test,predictions_SansIntercept),4)
Text_message("Le coefficient de détermination R² est de {}".format(r_squared))
Text_message("Vérification erreur moyenne : {} %".format(merged_df['% erreur'].mean().round(3)))
Tmessage("Modèle avec Intercept")
# Création du modèle de régression linéaire
model = smf.ols(formula='margin_low ~ height_right + margin_up + length ', data=train_df)
# On fit
results_AvecIntercept = model.fit()
# Prédictions sur Test
predictions_AvecIntercept = results_AvecIntercept.predict(X_test)
# Créez un DataFrame contenant les caractéristiques pour prédiction
data_to_predict = X_test
# Utilisez le modèle pour prédire les valeurs pour les données manquantes dans 'margin_low'
prediction_array = results_AvecIntercept.predict(data_to_predict)
merged_df = pd.merge(X_test, y_test, left_index=True, right_index=True)
# Remplacez les valeurs NaN dans 'margin_low' par les valeurs prédites
merged_df['margin_low_Predict'] = prediction_array
merged_df['% erreur'] = round(abs(100 - (merged_df['margin_low_Predict']*100 / merged_df['margin_low'])),2)
display(merged_df.head())
r_squared = round(r2_score(y_test,predictions_AvecIntercept),4)
Text_message("Le coefficient de détermination R² est de {}".format(r_squared))
Text_message("Vérification erreur moyenne : {} %".format(merged_df['% erreur'].mean().round(3)))
# ___________________________ Graphique de comparaison ___________________________
# Récupération des valeurs prédites et des résidus sans intercept
predicted_values = results_SansIntercept.fittedvalues
residuals = results_SansIntercept.resid
# Récupération des valeurs prédites et des résidus avec intercept
predicted_values1 = results_AvecIntercept.fittedvalues
residuals1 = results_AvecIntercept.resid
# Création d'un DataFrame pour le graphique des résidus
residuals_df = pd.DataFrame({'Valeurs prédites': predicted_values, 'Résidus': residuals})
residuals_df1 = pd.DataFrame({'Valeurs prédites': predicted_values1, 'Résidus': residuals1})
# Tracé du graphique des résidus
sns.set(rc={'axes.facecolor': 'white', 'figure.facecolor': 'white'})
plt.figure(figsize=(12,4))
sns.residplot(data=residuals_df, x='Valeurs prédites', y='Résidus', color='teal', scatter_kws={'alpha': 0.8}, lowess=True,
line_kws={'color': 'firebrick', 'linewidth': 6})
sns.residplot(data=residuals_df1, x='Valeurs prédites', y='Résidus', color='orange', scatter_kws={'alpha': 0.5}, lowess=True,
line_kws={'color': 'blue', 'linewidth': 2})
plt.xlabel('Valeurs prédites')
plt.ylabel('Résidus')
plt.title('Graphique des résidus pour une régression linéaire multiple', y=1,
fontdict={'size': 14, 'weight': 'bold', 'style': 'italic', 'color': 'firebrick'})
# Ajout de légendes factices pour le graphique
plt.scatter([], [], color='teal', label='Sans intercept') # Élément pour les points dispersés
plt.plot([], [], color='firebrick', linewidth=2, label='Régression lissée') # Élément pour la ligne de régression lissée
plt.scatter([], [], color='orange', label='Avec intercept') # Élément pour les points dispersés
plt.plot([], [], color='blue', linewidth=2, label='Régression lissée') # Élément pour la ligne de régression lissée
# Afficher la légende
plt.legend(loc='best') # Modifier la position de la légende selon vos besoins
plt.show()
# Conclusion:
Tmessage("Pas de différences notables entre les deux modèles", Color='blue', Align='center', Size='14')
| height_right | margin_up | length | margin_low | margin_low_Predict | % erreur | |
|---|---|---|---|---|---|---|
| 1301 | 104.19 | 3.25 | 111.99 | 5.72 | 4.882714 | 14.64 |
| 1028 | 103.93 | 3.49 | 111.34 | 5.38 | 5.093796 | 5.32 |
| 281 | 104.21 | 3.07 | 113.01 | 4.18 | 4.447908 | 6.41 |
| 665 | 104.44 | 2.99 | 113.16 | 4.54 | 4.465495 | 1.64 |
| 555 | 104.10 | 2.70 | 113.99 | 4.47 | 3.906402 | 12.61 |
| height_right | margin_up | length | margin_low | margin_low_Predict | % erreur | |
|---|---|---|---|---|---|---|
| 1301 | 104.19 | 3.25 | 111.99 | 5.72 | 4.867881 | 14.90 |
| 1028 | 103.93 | 3.49 | 111.34 | 5.38 | 5.145473 | 4.36 |
| 281 | 104.21 | 3.07 | 113.01 | 4.18 | 4.387276 | 4.96 |
| 665 | 104.44 | 2.99 | 113.16 | 4.54 | 4.361852 | 3.92 |
| 555 | 104.10 | 2.70 | 113.99 | 4.47 | 3.829804 | 14.32 |
Avec une erreur moyenne équivalente et un R² à 0.488, le modèle avec Intercept est validé
Tmessage("Imputation des valeurs 'margin_low' dans DF_NaN selon le modèle validé")
# Création d'un DataFrame contenant les caractéristiques pour prédiction
data_to_predict = DF_NaN[['height_right', 'margin_up', 'length']]
# Utilisation du modèle pour prédire les valeurs pour les données manquantes dans 'margin_low'
prediction_array = results_AvecIntercept.predict(data_to_predict)
# Remplacement des valeurs NaN dans 'margin_low' par les valeurs prédites
DF_NaN['margin_low'] = prediction_array.round(3)
display(DF_NaN.head(4))
Text_message("Nombres de lignes impactées : {} lignes".format(DF_NaN.shape[0]))
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|
| 72 | 1 | 171.94 | 103.89 | 103.45 | 4.329 | 3.25 | 112.79 |
| 99 | 1 | 171.93 | 104.07 | 104.18 | 4.371 | 3.14 | 113.08 |
| 151 | 1 | 172.07 | 103.80 | 104.38 | 4.452 | 3.02 | 112.93 |
| 197 | 1 | 171.45 | 103.66 | 103.80 | 4.335 | 3.62 | 113.27 |
Tmessage("--------------------------- Graphiques d'interprétation ------------------------",Color='blue')
DFC = DF_Complet.copy()
DFN = DF_NaN.copy()
# Création de la figure et des sous-graphiques
fig, axs = plt.subplots(1, 3, figsize=(12, 4))
# Tracé des graphiques dans chaque sous-graphique
plot_regression(DFC, DFN, 'length', "'margin-low' en fonction de 'length'", axs[0])
plot_regression(DFC, DFN, 'height_right', "'margin-low' en fonction de 'height_right'", axs[1])
plot_regression(DFC, DFN, 'margin_up', "'margin-low' en fonction de 'margin_up'", axs[2])
# Rétablir les valeurs originales pour éviter les modifications permanentes dans les DataFrames
DFC['is_genuine'] = DFC['is_genuine'].replace({'Faux': 0, 'Vrai': 1})
DFN['is_genuine'] = DFN['is_genuine'].replace({'Faux': 0, 'Vrai': 1})
# Récupérer les positions des axes
pos1 = axs[0].get_position()
pos2 = axs[1].get_position()
# Créer une légende commune
fig.legend(labels=['DF_Complet','Faux billets', 'Vrais billets', 'Régression linéaire',
'Interval de confiance', 'DF_NaN', 'Prédict Vrais billets', 'Prédict Faux billets'],
loc='upper center', bbox_to_anchor=((pos1.x0 + pos2.x1) / 1.5, pos1.y1-0.9), ncol=4)
plt.show()
Intégration des valeurs prédites dans le DataFrame
# Remplacer les valeurs NaN dans DF_F["margin_low"] par les valeurs correspondantes de DF_NaN
DF_F["margin_low"].fillna(DF_NaN["margin_low"], inplace=True)
# Vérification des valeurs manquantes restantes
DF_F.loc[DF_F["margin_low"].isna()]
| is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length |
|---|
Var1 = "margin_low"
Var2 = "length"
DF_kmeans = DF_F.copy()
# On affecte à nos X et y les données nécessaires
X = DF_kmeans.drop("is_genuine", axis=1)
y = DF_kmeans["is_genuine"]
# Définition du nombre de clusters avec graphique
n_cluster = kmeans_coude(X, graphique=True)
# Centrage et réduction
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Création d'un DF:
X_scaledGlobal = pd.DataFrame(X_scaled, columns=X.columns)
# On applique le modèle
k_means = KMeans(init="k-means++", n_clusters=n_cluster, random_state = random_state , n_init = 'auto' )
k_means.fit(X_scaled)
# On prédit suivant le modèle
prediction = k_means.predict(X_scaled)
# Ajout de la colonne 'Cluster'
X_scaledGlobal["cluster"] = prediction
# Calcule de la performance du modèle
test_f1 = f1_score(y, prediction, average='weighted')
Text_message("F1-score sur l'ensemble du DataFrame: {} %".format(round(test_f1*100,4)))
# Affichage du nuage de points (individus) en cluster avec les centroids
fig = plt.figure(figsize=(12, 4))
# Définir des couleurs pour chaque cluster
cluster_colors = ['indianred', 'lightseagreen']
# Nuage de points pour les individus
for cluster in range(n_cluster):
plt.scatter(X_scaledGlobal.loc[X_scaledGlobal['cluster'] == cluster, Var1],
X_scaledGlobal.loc[X_scaledGlobal['cluster'] == cluster, Var2],
c=cluster_colors[cluster], marker='o', s=30, edgecolors='w',
label='Vrais' if cluster == 1 else 'Faux')
# Centroids
plt.scatter(k_means.cluster_centers_[:, X_scaledGlobal.columns.get_loc(Var1)],
k_means.cluster_centers_[:, X_scaledGlobal.columns.get_loc(Var2)],
marker='p', s=150, c='darkred', edgecolors='w', label='Centroids')
plt.grid()
Tmessage('Clustering via K-means des variables les plus prédictives : {} et {}'.format(Var1, Var2), Color="firebrick", Size =14)
plt.xlabel(Var1)
plt.ylabel(Var2)
# Ajouter la légende
plt.legend()
plt.show()
# On réalise notre matrice de confusion
cf = confusion_matrix(y, X_scaledGlobal.cluster)
cm = ConfusionMatrixDisplay(cf)
# Enregistrement des valeurs de la matrice de confusion
true_negatives = cf[0, 0]
false_positives = cf[0, 1]
false_negatives = cf[1, 0]
true_positives = cf[1, 1]
# Etiquettes et fréquences
labels, counts = np.unique(k_means.labels_, return_counts=True)
Tmessage('- Cluster {}: {} Faux billets dont'.format(labels[0], counts[0]), Align='left', Color='black')
Tmessage("true_negatives : {} - false_negatives : {}".format(true_negatives,false_negatives),
Align = 'left', Color="firebrick", Size =14)
Tmessage('- Cluster {}: {} Vrais billets dont'.format(labels[1], counts[1]), Align='left', Color='black')
Tmessage("true_positives : {} - false_positives : {}".format(true_positives,false_positives),
Align = 'left', Color="firebrick", Size =14)
# Tracer la matrice de confusion
Tmessage("Matrice de Confusion", Color="firebrick", Size =14)
fig, ax = plt.subplots(figsize=(6, 4))
title = "is_genuine en fonction des 6 variables prédictives"
cm.plot(ax=ax, cmap=sns.color_palette("mako", as_cmap=True), xticks_rotation='horizontal')
ax.set_title(title, color='firebrick', fontsize=14)
plt.xlabel("Prédiction")
plt.ylabel("Vraie valeur")
plt.grid(False)
plt.show()
DF_kmeans = DF_F.copy()
# On affecte à nos X et y les données nécessaires
X = DF_kmeans.drop("is_genuine", axis=1)
y = DF_kmeans["is_genuine"]
# Centrage et réduction
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Création d'un DF:
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)
# On créer notre train set et test set
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size = 0.3, random_state=random_state)
# Définition du nombre de clusters avec graphique
#n_cluster = kmeans_coude(X_train, graphique=True)
scoreKmeans = 0
while scoreKmeans <0.5:
# On affecte le KMeans() à la variable model_Kmeans
model_Kmeans = KMeans(init="k-means++", n_clusters=n_cluster, n_init = 'auto' )
# On entraine lt model
model_Kmeans.fit(X_train)
# On calcule les centroides
cluster_centers = model_Kmeans.cluster_centers_
#if 'cluster' in X_test.columns:
# X_test = X_test.drop("cluster", axis=1)
# On stocke les predictions
prediction = model_Kmeans.predict(X_test)
prediction1 = model_Kmeans.predict(X_train)
# Ajout de la colonne 'Cluster'
X_test["cluster"] = prediction
X_train["cluster"] = prediction1
scoreKmeans = f1_score(y_test, prediction, average='weighted')
#print(scoreKmeans)
#print("silhouette_score Test : ", silhouette_score(X_test,prediction))
#print("silhouette_score Train : ", silhouette_score(X_train,prediction1))
Tmessage("Performance du modèle K-means sur le set Test", Color="blue", Size=20, Police='Scriptina')
# Affichage du nuage de points (individus) en cluster avec les centroids
fig = plt.figure(figsize=(12, 4))
# Définir des couleurs pour chaque cluster
cluster_colors = ['indianred', 'lightseagreen']
# Nuage de points pour les individus
for cluster in range(n_cluster):
plt.scatter(X_test.loc[X_test['cluster'] == cluster, Var1],
X_test.loc[X_test['cluster'] == cluster, Var2],
c=cluster_colors[cluster], marker='o', s=30, edgecolors='w',
label='Vrais' if cluster == 1 else 'Faux')
# Centroids
plt.scatter(model_Kmeans.cluster_centers_[:, X_test.columns.get_loc(Var1)],
model_Kmeans.cluster_centers_[:, X_test.columns.get_loc(Var2)],
marker='p', s=150, c='darkred', edgecolors='w', label='Centroids')
plt.grid()
Tmessage('Clustering via K-means des variables les plus prédictives : {} et {}'.format(Var1, Var2), Color="firebrick", Size =14)
plt.xlabel(Var1)
plt.ylabel(Var2)
# Ajouter la légende
plt.legend()
plt.show()
# Mesure de la précision du modèle
test_f = f1_score(y_test, prediction, average='weighted')
Tmessage("Précision du modèle sur le set Test {} %".format(round(test_f*100,3)), Align='left', Color="teal")
# On réalise notre matrice de confusion
cf = confusion_matrix(y_test, X_test.cluster)
cm = ConfusionMatrixDisplay(cf)
# Enregistrement des valeurs de la matrice de confusion
true_negatives = cf[0, 0]
false_positives = cf[0, 1]
false_negatives = cf[1, 0]
true_positives = cf[1, 1]
# Etiquettes et fréquences
#labels, counts = np.unique(k_means.labels_, return_counts=True)
labels, counts = np.unique(prediction, return_counts=True)
Tmessage('- Cluster {}: {} Faux billets dont'.format(labels[0], counts[0]), Align='left', Color='black')
Tmessage("true_negatives : {} - false_negatives : {}".format(true_negatives,false_negatives),
Align = 'left', Color="firebrick", Size =14)
Tmessage('- Cluster {}: {} Vrais billets dont'.format(labels[1], counts[1]), Align='left', Color='black')
Tmessage("true_positives : {} - false_positives : {}".format(true_positives,false_positives),
Align = 'left', Color="firebrick", Size =14)
classes = ["Vrai", "Faux"]
# Tracer la matrice de confusion
Tmessage("Matrice de Confusion", Color="firebrick", Size =14)
fig, ax = plt.subplots(figsize=(6, 4))
title = "is_genuine en fonction des 6 variables prédictives"
#sns.heatmap(cm, annot=True, fmt="", cmap="mako", xticklabels=classes, yticklabels=classes)
cm.plot(ax=ax, cmap=sns.color_palette("mako", as_cmap=True), xticks_rotation='horizontal')
ax.set_title(title, color='firebrick', fontsize=14)
plt.xlabel("Prédiction")
plt.ylabel("Vraie valeur")
plt.grid(False)
# Modifier les étiquettes des axes
ax.set_xticklabels(["Faux", "Vrai"])
ax.set_yticklabels(["Faux", "Vrai"])
plt.show()
Tmessage("Performance du modèle K-means sur le set Train", Color="blue", Size=20, Police='Scriptina')
# Affichage du nuage de points (individus) en cluster avec les centroids
fig = plt.figure(figsize=(12, 4))
# Définir des couleurs pour chaque cluster
cluster_colors = ['indianred', 'lightseagreen']
# Nuage de points pour les individus
for cluster in range(n_cluster):
plt.scatter(X_train.loc[X_train['cluster'] == cluster, Var1],
X_train.loc[X_train['cluster'] == cluster, Var2],
c=cluster_colors[cluster], marker='o', s=30, edgecolors='w',
label='Vrais' if cluster == 1 else 'Faux')
# Centroids
plt.scatter(k_means.cluster_centers_[:, X_train.columns.get_loc(Var1)],
k_means.cluster_centers_[:, X_train.columns.get_loc(Var2)],
marker='p', s=150, c='darkred', edgecolors='w', label='Centroids')
plt.grid()
Tmessage('Clustering via K-means des variables les plus prédictives : {} et {}'.format(Var1, Var2), Color="firebrick", Size =14)
plt.xlabel(Var1)
plt.ylabel(Var2)
# Ajouter la légende
plt.legend()
plt.show()
# Mesure de la précision du modèle
test_f1 = f1_score(y_train, prediction1, average='weighted')
Tmessage("Précision du modèle sur le set Train {} %".format(round(test_f1*100,3)), Align='left', Color="teal")
# On réalise notre matrice de confusion
cf = confusion_matrix(y_train, X_train.cluster)
cm = ConfusionMatrixDisplay(cf)
# Enregistrement des valeurs de la matrice de confusion
true_negatives = cf[0, 0]
false_positives = cf[0, 1]
false_negatives = cf[1, 0]
true_positives = cf[1, 1]
# Etiquettes et fréquences
#labels, counts = np.unique(k_means.labels_, return_counts=True)
labels, counts = np.unique(prediction1, return_counts=True)
Tmessage('- Cluster {}: {} Faux billets dont'.format(labels[0], counts[0]), Align='left', Color='black')
Tmessage("true_negatives : {} - false_negatives : {}".format(true_negatives,false_negatives),
Align = 'left', Color="firebrick", Size =14)
Tmessage('- Cluster {}: {} Vrais billets dont'.format(labels[1], counts[1]), Align='left', Color='black')
Tmessage("true_positives : {} - false_positives : {}".format(true_positives,false_positives),
Align = 'left', Color="firebrick", Size =14)
# Tracer la matrice de confusion
Tmessage("Matrice de Confusion", Color="firebrick", Size =14)
fig, ax = plt.subplots(figsize=(6, 4))
title = "is_genuine en fonction des 6 variables prédictives"
cm.plot(ax=ax, cmap=sns.color_palette("mako", as_cmap=True), xticks_rotation='horizontal')
ax.set_title(title, color='firebrick', fontsize=14)
plt.grid(False)
plt.xlabel("Prédiction")
plt.ylabel("Vraie valeur")
# Modifier les étiquettes des axes
ax.set_xticklabels(["Faux", "Vrai"])
ax.set_yticklabels(["Faux", "Vrai"])
plt.show()
Var1 = "margin_low"
Var2 = "length"
Tmessage("Visualisation via K-means des variables les plus prédictives sur X-train", Color='black')
yt = pd.DataFrame(y)
yt.reset_index(drop=True, inplace=True)
# Ajouter les labels de cluster au DataFrame
X_train['cluster'] = model_Kmeans.labels_
# Affichage du nuage de points (individus) en cluster avec les centroids
fig = plt.figure(figsize=(12, 4))
# Définir des couleurs pour chaque cluster
cluster_colors = ['indianred', 'lightseagreen']
# Nuage de points pour les individus
for cluster in range(n_cluster):
cluster_data = X_train.loc[X_train['cluster'] == cluster]
cluster_data = pd.merge(cluster_data, yt, left_index=True, right_index=True)
plt.scatter(cluster_data[Var1], cluster_data[Var2],
c=cluster_colors[cluster], marker='o', s=30, edgecolors='w',
label='Vrais' if cluster == 1 else 'Faux')
# Afficher les indices dans la série y
for i, index in enumerate(cluster_data.index):
plt.text(cluster_data.loc[index, Var1], cluster_data.loc[index, Var2], str(cluster_data.loc[index,'is_genuine']),
fontsize=8, ha='center', va='center')
# Centroids
plt.scatter(model_Kmeans.cluster_centers_[:, X_train.columns.get_loc(Var1)],
model_Kmeans.cluster_centers_[:, X_train.columns.get_loc(Var2)],
marker='p', s=150, c='darkred', edgecolors='w', label='Centroids')
plt.grid()
plt.title('Clustering avec KMeans en fonction de {} et {}'.format(Var1, Var2), color="firebrick", size=14)
plt.xlabel(Var1)
plt.ylabel(Var2)
# Ajouter la légende
plt.legend()
plt.show()
# Préparation des données:
scaler=StandardScaler()
DF_PCA = DF_F.iloc[:,1:7]
X_norm=scaler.fit_transform(DF_PCA)
# PCA
pca=PCA()
pca.fit(X_norm)
features = DF_PCA.columns
n_components = len(pca.explained_variance_ratio_)
Tmessage('Analyse des composantes principales', Color='blue', Size=20)
# Vérification moyennes à 0 et écarts type à 1 :
Text_message("Vérification moyennes à 0 et écarts type à 1")
idx = ["mean", "std"]
display(pd.DataFrame(X_norm).describe().round(2).loc[idx, :])
# On instancie notre ACP :
pca = PCA(n_components=n_components)
# On l'entraine sur les données scalées :
pca.fit(X_norm)
# Get the centroids
kmeans = KMeans(n_clusters=2, random_state=random_state)
kmeans.fit(X_norm)
centroids = pca.transform(kmeans.cluster_centers_)
# Variable avec la liste de nos composantes :
x_list = range(1, n_components+1)
# Enregistrement dans une variable :
scree = (pca.explained_variance_ratio_*100).round(2)
scree_cum = scree.cumsum().round()
# --------------------------------------------------- Analyse des composantes principales ---------------------------------
# Affichage des graphiques
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.bar(x_list, scree, color=plt.cm.Blues(scree / max(scree)))
plt.plot(x_list, scree_cum, c="firebrick", marker='o')
plt.xlabel("Rang de l'axe d'inertie")
plt.ylabel("Pourcentage d'inertie")
plt.title("Eboulis des valeurs propres", color='firebrick', fontsize=10, fontweight='bold')
plt.grid(color='gray', linestyle='--')
plt.subplot(1, 2, 2)
# Calcul de la variance expliquée par composante
explained_variance = pca.explained_variance_ratio_
# Création d'un graphique pour la méthode du coude
plt.plot(range(1, len(explained_variance) + 1), explained_variance, linestyle='-', c="firebrick", marker='o')
plt.xlabel('Nombre de composantes')
plt.ylabel('Variance expliquée')
plt.title('Variance expliquée par nombre de composantes\n Méthode du coude', color='firebrick', fontsize=10, fontweight='bold')
plt.grid(color='gray', linestyle='--')
# Ajustement des ticks de l'axe des abscisses
plt.xticks(np.arange(1, len(explained_variance) + 1, 1))
plt.show()
# Affichage n-component retenu :
Tmessage('Cumul des valeurs propres : {}'.format(scree_cum), Color='teal')
# DF des composantes principales
pcs = pca.components_
pcs = pd.DataFrame(pcs)
# Ajout des F :
pcs.columns = features
pcs.index = [f"F{i}" for i in x_list]
pcs.round(2)
Tmessage("Composantes principales")
display(pcs)
# Représentation graphique :
fig, ax = plt.subplots(figsize=(12, 3))
sns.heatmap(pcs.T, vmin=-1, vmax=1, annot=True, cmap="coolwarm", fmt="0.2f")
plt.title('Heatmap des composantes principales', color='firebrick', fontsize=14, fontweight='bold')
plt.show()
# -------------------------------------------- Cercle des corrélations des composantes principales ----------------------------
Tmessage('-------------------------------------------------------------------------------------------', Color='black', Size=20)
Tmessage('Projection des individus sur le premier plan factoriel', Color='blue', Size=20)
# Préparation du set "composantes retenues"
pcs = pcs.T
pcs_final = pcs[['F1','F2']]
# Représentation graphique :
fig, ax = plt.subplots(figsize=(12, 2))
sns.heatmap(pcs_final, vmin=-1, vmax=1, annot=True, cmap="coolwarm", fmt="0.4f")
plt.title('Heatmap des composantes principales suffisantes ({} %)'.format(scree_cum[1]), color='firebrick', fontsize=14,
fontweight='bold')
plt.show()
features = DF_F.iloc[:,1:7].columns
# correlation_graph(pca, x_y, features, palette="rocket", legend_fontsize=12, label_fontsize=10, Indicsize=8, arrow_alpha=0.8):
# Afficher le cercle de corrélation pour F1 et F2
x_y = 0,1
correlation_graph(pca, (x_y), features, palette="viridis")
# Projection
X_proj = pca.transform(X_norm)
# Plans_Factoriels
Plans_Factoriels(X_proj, x_y, pca, clusters=X_scaledGlobal["cluster"], centroids=centroids, figsize=(10,4), marker="o",
palette=['darkslategrey', 'lightseagreen'])
| 0 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| mean | -0.0 | 0.0 | -0.0 | 0.0 | -0.0 | 0.0 |
| std | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 | 1.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| F1 | -0.084405 | 0.330424 | 0.393509 | 0.507553 | 0.439674 | -0.527184 |
| F2 | 0.941360 | 0.307524 | 0.108083 | -0.071863 | -0.005511 | 0.048925 |
| F3 | -0.288752 | 0.885328 | -0.160049 | -0.112410 | -0.268913 | 0.149166 |
| F4 | -0.101564 | -0.051433 | 0.867907 | -0.091625 | -0.440962 | 0.175884 |
| F5 | -0.113900 | 0.098681 | 0.233638 | -0.563831 | 0.714347 | 0.307416 |
| F6 | 0.007136 | 0.007667 | 0.002066 | 0.631101 | 0.172057 | 0.756302 |
DF_kmeans = DF_F.copy()
T_size = 0.3
# On affecte à nos X et y les données nécessaires
X = DF_kmeans.drop("is_genuine", axis=1)
y = DF_kmeans["is_genuine"]
# Centrage et réduction
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Création d'un DF:
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)
# On créer notre train set et test set
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size = T_size, random_state=random_state)
# Création du modèle et vérification que les clusters sont répartis de la bonne façon à l'aide du f1_score
scoreKmeans = 0
while scoreKmeans <0.5:
# On applique le modèle
model_Kmeans = KMeans(init="k-means++", n_clusters=n_cluster, n_init = 'auto' )
#model_Kmeans =KMeans(n_cluster)
# On entraine lt model
model_Kmeans.fit(X_train)
# On calcule les centroides
#cluster_centers = pca.transform(model_Km.cluster_centers_)
# Get the centroids
#kmeans = KMeans(n_cluster)
#kmeans.fit(X_norm)
#centroids = pca.transform(model_Km.cluster_centers_)
if 'cluster' in X_test.columns:
X_test = X_test.drop("cluster", axis=1)
# On stocke les predictions
prediction = model_Kmeans.predict(X_test)
# Ajout de la colonne 'Cluster'
X_test["cluster"] = prediction
scoreKmeans = f1_score(y_test, prediction, average='weighted')
# print(scoreKmeans)
# Get the centroids
centroids = pca.transform(model_Kmeans.cluster_centers_)
# Affichage du dataset :
Tmessage("Affectation des clusters au set test ({} % du DataFrame)".format(round(T_size*100),0))
display(X_test)
# Calcul des métriques sur les données de test
test_precision_Kmeans = precision_score(y_test, prediction, average='weighted')
test_recall_Kmeans = recall_score(y_test, prediction, average='weighted')
F1_Kmeans = f1_score(y_test, prediction, average='weighted')
# Affichage des résultats
Text_message("F1-score sur l'ensemble de test: {} %".format(round(F1_Kmeans*100,4)))
#print("Précision sur l'ensemble d'entraînement:", train_precision)
Text_message("Précision sur l'ensemble de test: {}".format(round((test_precision_Kmeans),4)))
#print("\nRappel sur l'ensemble d'entraînement:", train_recall)
Text_message("Rappel sur l'ensemble de test: {}".format(round((test_recall_Kmeans),4)))
# Matrice de confusion
cf = confusion_matrix(y_test, X_test.cluster)
cm = ConfusionMatrixDisplay(cf)
# Définition du titre
title = "Matrice de Confusion"
# Tracer la matrice de confusion avec un titre personnalisé et en changeant la palette de couleurs
fig, ax = plt.subplots(figsize=(10, 4))
cm.plot(ax=ax, cmap='mako', xticks_rotation='horizontal') # Changer 'Blues' à la palette de couleur désirée
ax.set_title(title, color='firebrick', fontsize=14) # Définir la taille de la police du titre
plt.grid(False)
plt.show()
# Projection
x_y = 0,1
X_test1 = X_test.drop("cluster", axis=1)
#X_norm=scaler.fit_transform(X_test1)
#pca=PCA()
#pca.fit(X_norm)
X_proj = pca.transform(X_test1)
Plans_Factoriels(X_proj, x_y, pca, clusters=X_test["cluster"], centroids=centroids, figsize=(10,4), marker="o",
palette=['teal','grey'])
#scaler=StandardScaler()
scaler=MinMaxScaler()
# Réduction de la dimension des données à 2 dimensions avec T-SNE
tsne = TSNE(n_components=n_cluster, random_state=random_state)
X_tsne = tsne.fit_transform(X_test1)
# Ajout de l'indice du cluster dans les données pour la visualisation
X_tsne_with_clusters = np.column_stack((X_tsne, prediction))
# Création d'un DataFrame pour faciliter la visualisation
df_tsne_clusters = pd.DataFrame(data=X_tsne_with_clusters, columns=['Dimension 1', 'Dimension 2', 'Cluster'])
# Visualisation des clusters
Tmessage('Visualisation des clusters avec T-SNE', Color='teal', Size = 18)
plt.figure(figsize=(10, 3))
#scatter = plt.scatter(df_tsne_clusters['Dimension 1'], df_tsne_clusters['Dimension 2'],
#c=df_tsne_clusters['Cluster'], cmap=ListedColormap(['teal', 'gray']))
scatter = sns.scatterplot(x='Dimension 1', y='Dimension 2', data=df_tsne_clusters, hue='Cluster',
palette=['teal', 'firebrick'])
plt.xlabel('Dimension 1')
plt.ylabel('Dimension 2')
# Obtenir les éléments de légende
handles, labels = scatter.get_legend_handles_labels()
# Utilisation des éléments de légende pour créer la légende
plt.legend(handles, labels, title='Cluster')
#plt.legend(*scatter.legend_elements(), title='Cluster')
plt.show()
#df_tsne_clusters
# Calcul du score de silhouette
silhouette_avg = silhouette_score(X_test, prediction)
Text_message("Score de silhouette : {}".format(round(silhouette_avg,4)))
# Calcul du Davies-Bouldin Index
db_index = davies_bouldin_score(X_test, prediction)
Text_message("Davies-Bouldin Index : {}".format(round(db_index,4)))
# Calcul de la Calinski-Harabasz Index
ch_index = calinski_harabasz_score(X_test, prediction)
Text_message("Calinski-Harabasz Index : {}".format(round(ch_index,4)))
# Calcul de l'Adjusted Rand Index (ARI)
ari = adjusted_rand_score(y_test, prediction)
Text_message("Adjusted Rand Index (ARI) : {}".format(round(ari,4)))
| diagonal | height_left | height_right | margin_low | margin_up | length | cluster | |
|---|---|---|---|---|---|---|---|
| 1212 | -0.191548 | 1.003691 | 1.473628 | 0.328705 | 0.684084 | -0.640159 | 0 |
| 954 | -0.617647 | -1.334617 | -1.014709 | -1.461412 | 0.727236 | 0.104878 | 1 |
| 1207 | -0.814308 | 0.302198 | 0.674903 | 0.541092 | 0.986152 | -1.144493 | 0 |
| 921 | -1.961498 | -1.033977 | 2.579556 | -0.475331 | -1.171478 | 0.528977 | 1 |
| 89 | -0.060441 | -1.802278 | -0.308144 | -0.369137 | 0.166253 | 0.425818 | 1 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 830 | -1.535399 | -0.299081 | -0.215984 | -0.247773 | 0.727236 | 1.136469 | 1 |
| 1350 | -1.895944 | -0.833551 | -0.676787 | 1.117570 | 1.201915 | -1.236190 | 0 |
| 1044 | -1.338738 | 0.502625 | -0.277424 | -0.035387 | 1.158762 | -1.236190 | 0 |
| 705 | 1.643956 | -0.933764 | 0.306260 | -0.338796 | 0.295710 | 1.090621 | 1 |
| 417 | 2.528931 | -0.031846 | 0.797784 | -1.127662 | 0.209405 | 0.964538 | 1 |
450 rows × 7 columns
Un ARI à 0.938 indique une correspondance très forte entre les deux ensembles d'étiquettes. Le CHI indique une bonne séparation entre les clusters dans l'algorithme de clustering
Pour ce projet, il est intéressant d'obtenir de bons résultats avec le K-mean (Algorithme non supervisé)
Régression logistique avec Statsmodels
On utilise la fonction 'backward_selected_log' pour définir le nombre de variables prédictives¶
# On utilise la fonction my_backward_selected_logistic afin de trouver les varibles descriptives les plus pertinentes
# Suppression des variables dont la p-value > 5%
columns = ['margin_low','diagonal','is_genuine','height_left','height_right','margin_up','length']
reg_backward = backward_selected_log(DF_F[columns], 'is_genuine', 0.05)
_______________________________
is_genuine ~ height_right + length + diagonal + margin_up + margin_low + height_left + 1
Optimization terminated successfully.
Current function value: 0.028229
Iterations 13
remove diagonal (p-value: 0.922 )
_______________________________
is_genuine ~ height_right + length + margin_up + margin_low + height_left + 1
Optimization terminated successfully.
Current function value: 0.028233
Iterations 12
remove height_left (p-value: 0.112 )
_______________________________
is_genuine ~ height_right + length + margin_up + margin_low + 1
Optimization terminated successfully.
Current function value: 0.029097
Iterations 12
is the final model!
| Dep. Variable: | is_genuine | No. Observations: | 1500 |
|---|---|---|---|
| Model: | Logit | Df Residuals: | 1495 |
| Method: | MLE | Df Model: | 4 |
| Date: | Thu, 25 Jul 2024 | Pseudo R-squ.: | 0.9543 |
| Time: | 19:54:59 | Log-Likelihood: | -43.646 |
| converged: | True | LL-Null: | -954.77 |
| Covariance Type: | nonrobust | LLR p-value: | 0.000 |
| coef | std err | z | P>|z| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | -321.8686 | 139.627 | -2.305 | 0.021 | -595.533 | -48.204 |
| height_right | -2.8257 | 1.080 | -2.617 | 0.009 | -4.942 | -0.709 |
| length | 6.0078 | 0.831 | 7.229 | 0.000 | 4.379 | 7.637 |
| margin_up | -10.1899 | 2.077 | -4.906 | 0.000 | -14.260 | -6.119 |
| margin_low | -6.0361 | 0.903 | -6.687 | 0.000 | -7.805 | -4.267 |
Possibly complete quasi-separation: A fraction 0.51 of observations can be
perfectly predicted. This might indicate that there is complete
quasi-separation. In this case some parameters will not be identified.
Performance du modèle Logit() de Statsmodels
DF_RLog = DF_F.copy()
#Columns = ['diagonal','height_left', 'height_right', 'margin_low', 'margin_up', 'length']
Columns = ['height_right', 'margin_low', 'margin_up', 'length']
# On affecte à nos X et y les données nécessaires
X = DF_RLog[Columns]
# Ajout d'une colonne constante pour l'intercept
X = sm.add_constant(X)
y = DF_RLog["is_genuine"]
# On créer notre train set et test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state=random_state)
#régression logistique
Res_Log = Logit(endog=y_train,exog=X_train).fit()
display(Res_Log.summary())
# Effectuer des prédictions sur les données de test
y_pred = Res_Log.predict(X_test)
# Convertir les probabilités prédites en classes (0 ou 1)
y_pred_class = (y_pred > 0.5).astype(int) # Choix du seuil de 0.5 pour la classification binaire
# Calculer les métriques
accuracy = round(accuracy_score(y_test, y_pred_class),4)
precision = round(precision_score(y_test, y_pred_class),4)
recall = round(recall_score(y_test, y_pred_class),4)
f1 = round(f1_score(y_test, y_pred_class),6)
Text_message("Accuracy : {}".format(accuracy))
Text_message("Précision : {}".format(precision))
Text_message("Recall : {}".format(recall))
Text_message("Le score f1 du modèle sur les données Test est de : {}%".format(f1*100))
Optimization terminated successfully.
Current function value: 0.031837
Iterations 12
| Dep. Variable: | is_genuine | No. Observations: | 1200 |
|---|---|---|---|
| Model: | Logit | Df Residuals: | 1195 |
| Method: | MLE | Df Model: | 4 |
| Date: | Thu, 25 Jul 2024 | Pseudo R-squ.: | 0.9501 |
| Time: | 19:55:03 | Log-Likelihood: | -38.204 |
| converged: | True | LL-Null: | -765.20 |
| Covariance Type: | nonrobust | LLR p-value: | 0.000 |
| coef | std err | z | P>|z| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| const | -278.9557 | 157.068 | -1.776 | 0.076 | -586.804 | 28.892 |
| height_right | -2.6995 | 1.222 | -2.208 | 0.027 | -5.095 | -0.304 |
| margin_low | -5.9038 | 1.008 | -5.854 | 0.000 | -7.880 | -3.927 |
| margin_up | -9.6090 | 2.126 | -4.521 | 0.000 | -13.775 | -5.443 |
| length | 5.4885 | 0.811 | 6.767 | 0.000 | 3.899 | 7.078 |
Possibly complete quasi-separation: A fraction 0.48 of observations can be
perfectly predicted. This might indicate that there is complete
quasi-separation. In this case some parameters will not be identified.
Performance du modèle LogisticRegression() de Sklearn
from sklearn.metrics import r2_score
# On affecte à nos X et y les données nécessaires en retirant les variables descriptives non significatives
X = DF_F.drop(["is_genuine","diagonal","height_left"], axis=1)
y = DF_F["is_genuine"]
# On définit notre Train Set et notre Test Set
X_train ,X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=random_state)
# On définit notre model
model_LR = LogisticRegression()
# On entraine notre model
model_RL = model_LR.fit(X_train, y_train)
# On enregistre les prédictions dans une variable y_pred
y_pred = model_RL.predict(X_test)
# On vérifie le score de notre model sur les données Test (F1 score)
accuracy = round(accuracy_score(y_test, y_pred),4)
precision = round(precision_score(y_test, y_pred),4)
recall = round(recall_score(y_test, y_pred),4)
f1 = round(f1_score(y_test, y_pred),6)
Text_message("Accuracy : {}".format(accuracy))
Text_message("Précision : {}".format(precision))
Text_message("Recall : {}".format(recall))
Text_message("Le score f1 du modèle sur les données Test est de : {}%".format(f1*100))
# Calcul du R²
r2 = r2_score(y_test, y_pred)
Text_message("Le coefficient de détermination R² est : {}".format(r2.round(4)))
DF_F1 = DF_F.copy()
Seuil = 0.5
test_size = 0.2
V_pred = ["height_right", "margin_low", "margin_up", "length"]
# Utilisation de la fonction de comparaison Statsmodels/SKlearn
# Mat_RegLog_Seuil(DF_F1, Seuil = Seuil, Set=['X_test'], test_size=test_size, V_pred = V_pred, random_state = random_state)
Mat_RegLog_Seuil(DF_F1, Seuil = Seuil, test_size=test_size, V_pred = V_pred, random_state = random_state)
Optimization terminated successfully.
Current function value: 0.031837
Iterations 12
Les 2 modèles ont les mêmes performances
Appliquons les métriques sur le modèle Sklearn
Seuil = 0.5
test_size = 0.2
# On affecte à nos X et y les données nécessaires en retirant les variables descriptives non significatives
X = DF_F.drop(["is_genuine","diagonal","height_left"], axis=1)
# Centrage et réduction
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# Création d'un DF:
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)
y = DF_F["is_genuine"]
# On définit notre Train Set et notre Test Set
X_train ,X_test, y_train, y_test = train_test_split(X_scaled,y, test_size=test_size, random_state=random_state)
# On définit notre model
model_LR = LogisticRegression()
# On entraine notre model
model_LR.fit(X_train, y_train)
y_hat_proba = model_LR.predict_proba(X_test)[:,1]
y_Seuil = [ 0 if value < Seuil else 1 for value in y_hat_proba ]
# Matrice de confusion
cm = confusion_matrix(y_test, y_Seuil)
true_negative, false_positive, false_negative, true_positive = cm.ravel()
plt.figure(figsize=(12, 4))
sns.heatmap(cm, annot = True, fmt = ".3g", cmap = sns.color_palette("rocket", as_cmap=True),
linecolor = "white", linewidths = 0.3, xticklabels = ["Faux","Vrai"], yticklabels=["0","1"])
plt.xlabel("Prédictions")
plt.ylabel("Réels")
plt.title("Matrice de confusion de la regression logistique Sklearn\navec un seuil = {}".format(round(Seuil,3)),
color='firebrick')
plt.show()
# Métriques de performance:
Tmessage("Métriques de performance")
F1_RLg = f1_score(y_test, y_Seuil)
Accu_Rlg = round(accuracy_score(y_test, y_Seuil), 4)
#Accu_Rlg = accuracy_score(y_test, y_Seuil).round(4)
Prec_Rlg = precision_score(y_test, y_Seuil).round(4)
Recall_Rlg = recall_score(y_test, y_Seuil).round(4)
Tmessage("F1_score sur le set Test: {} %".format(round(F1_RLg*100,4)), Color='black', Align='left')
Text_message("Nombre de prédictions correctes sur le nombre total d'échantillons - Accuracy : {}".format(Accu_Rlg))
Text_message("Précision des prédictions positives - Precision: {}".format(Prec_Rlg))
Text_message("Capacité du modèle à capturer tous les exemples positifs - Recall: {}".format(Recall_Rlg))
# Analyse des performances du modèle de classification => l'histogramme des probabilités des prédictions
# Obtenir les probabilités prédites pour la classe positive
y_hat_proba = model_LR.predict_proba(X_test)[:,1]
# Définir les pas de l'abscisse à 0.05
bins = np.arange(0, 1.05, 0.02)
sns.set(rc={'axes.facecolor': 'white', 'figure.facecolor': 'white'})
plt.figure(figsize=(12,4))
plt.title('Probabilités des prédictions', y=1,
fontdict={'size': 12, 'weight': 'bold', 'style': 'italic', 'color': 'firebrick'})
# Afficher l'histogramme des probabilités prédites
sns.histplot(y_hat_proba, bins=bins, kde=True) # kde=False pour supprimer l'estimation de densité
plt.xlabel('Probabilités prédites')
plt.ylabel('Fréquence')
plt.show()
# Adaptation du DF:
df_Taille_Adapt = DF_F1.dropna()
# Courbe R.O.C.:
fpr, tpr, _ = roc_curve(df_Taille_Adapt["is_genuine"],df_Taille_Adapt["proba"])
roc_auc = roc_auc_score(df_Taille_Adapt["is_genuine"],df_Taille_Adapt["proba"])
# Graphique:
Tmessage("Courbe R.O.C.", Size=16)
plt.figure(figsize=(10, 4))
plt.plot(fpr, tpr, color="firebrick", linewidth=2.5, label="aire sous la courbe = %0.2f" % roc_auc)
plt.plot([0, 1], [0, 1],color="grey", linestyle=":")
plt.xlim([0, 1])
plt.ylim([0, 1])
plt.legend(loc = "lower right")
plt.ylabel("Taux de vrais positifs")
plt.xlabel("Taux de faux positifs")
plt.grid(True, linestyle='--', color='gray', linewidth=0.5)
plt.axis('on')
plt.show()
Tmessage("Capacité du modèle à discriminer entre les classes - ROC-AUC: {}".format(round(roc_auc,6)), Color ='black',
Align='left')
# Utilisation de la fonction learning_curve pour générer les données de courbe d'apprentissage
# nombre de splits pour la validation croisée (cv)
cv = 10
train_sizes, train_scores, test_scores = learning_curve(
model_RL, X_train, y_train, cv=cv, train_sizes=np.linspace(0.1, 1.0, 10), scoring=make_scorer(accuracy_score))
# Calcul des scores moyens et des écart-types pour l'ensemble d'entraînement et l'ensemble de test
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
# Affichage des courbes d'apprentissage
Tmessage("Courbes d'apprentissage ({} splits)".format(cv), Size=16)
plt.figure(figsize=(10, 4))
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1, color="b")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="r")
plt.plot(train_sizes, train_scores_mean, 'o-', color="b", label="Score d'entraînement")
plt.plot(train_sizes, test_scores_mean, 'o-', color="r", label="Score de validation")
plt.xlabel("Taille de l'ensemble d'entraînement")
plt.ylabel("Score")
plt.legend(loc="best")
plt.show()
# Enregistrement du fichier de référence:
DF_F.to_csv('DF_billets_reference.csv', index=False) # Sauvegarde du DataFrame 'df' en fichier CSV
Tmessage("Algorithme de régression logistique", Size=16)
# Affichage des résultats
Tmessage("F1_score sur le set Test: {} %".format(round(F1_RLg*100,4)), Color='teal', Align='left')
Tmessage("Nombre de prédictions correctes sur le nombre total d'échantillons - Accuracy : {}".format(Accu_Rlg),
Color='black', Align='left', Size = 12)
Tmessage("Précision des prédictions positives - Precision: {}".format(Prec_Rlg), Color='black', Align='left', Size = 12)
Tmessage("Capacité du modèle à capturer tous les exemples positifs - Recall: {}".format(Recall_Rlg),
Color='black', Align='left', Size = 12)
display(model_RL)
Tmessage("Algorithme K_means", Size=16)
# Affichage des résultats
Tmessage("F1-score sur l'ensemble de test: {} %".format(round(F1_Kmeans*100,4)), Color='teal', Align='left')
Tmessage("Précision sur l'ensemble de test: {}".format(round((test_precision_Kmeans),4)), Color='black',
Align='left', Size = 12)
Tmessage("Rappel sur l'ensemble de test: {}".format(round((test_recall_Kmeans),4)), Color='black', Align='left', Size = 12)
model_Kmeans
LogisticRegression()In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LogisticRegression()
KMeans(n_clusters=2)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KMeans(n_clusters=2)
Avec un meilleur score, la régression logistique sera ulisée pour identifier les billets
Création d'un fichier Test
# ----------------------------------- Création d'un fichier test à partir de DF_F ---------------------------------------------
import random
# Création d'un DF de simulation
# Filtrer les lignes où is_genuine = 0 et is_genuine = 1
df_is_genuine_0 = DF_F[DF_F['is_genuine'] == 0]
df_is_genuine_1 = DF_F[DF_F['is_genuine'] == 1]
Pourcentage = 0.4
Nbr_Billets = 20
random_state1 = random.randint(0, 1000)
# Sélectionner aléatoirement des lignes où is_genuine = 0
random_0 = df_is_genuine_0.sample(frac=Pourcentage, random_state=random_state1)
# Sélectionner aléatoirement des lignes où is_genuine = 1
random_1 = df_is_genuine_1.sample(frac=1-Pourcentage, random_state=random_state1)
# Concaténer les deux sélections pour obtenir un DataFrame final avec 50 lignes
random_rows = pd.concat([random_0, random_1])
# Sélectionner aléatoirement 50 lignes parmi les 50 obtenues
DF_Test = random_rows.sample(n=Nbr_Billets, random_state=random_state)
DF_Test = DF_Test.reset_index()
DF_Test = DF_Test.drop("index", axis=1)
# Ajout de lignes aberrantes
data_to_append = [
{'is_genuine': 0, "diagonal": 172, "height_left": 0, "height_right": 103.59, "margin_low": 4.080, "margin_up": 0, "length": 114.09},
{'is_genuine': 0, "diagonal": 172.00, "height_left": 104.35, "height_right": 103.29, "margin_low": 3.730, "margin_up": 3.11, "length": 999.18},
{'is_genuine': 0, "diagonal": 172.58, "height_left": 103.99, "height_right": 150, "margin_low": 4.430, "margin_up": 3.07, "length": 112.79},
{'is_genuine': 0, "diagonal": 171.85, "height_left": 103.93, "height_right": 103.81, "margin_low": 4, "margin_up": 3.12, "length": 112.8},
{'is_genuine': 0, "diagonal": 500.85, "height_left": 103.93, "height_right": 103.81, "margin_low": 0, "margin_up": 3.12, "length": 112.8},
{'is_genuine': 0, "diagonal": 171.85, "height_left": 20, "height_right": 103.81, "margin_low": 4, "margin_up": 30.12, "length": 112.8},
{'is_genuine': 0, "diagonal": 171.85, "height_left": 103.93, "height_right": 103.81, "margin_low": 40, "margin_up": 3.12, "length": 112.8},
{'is_genuine': 0, "diagonal": 800, "height_left": 500, "height_right": 300, "margin_low": 40, "margin_up": 50, "length": 800},
{'is_genuine': 0, "diagonal": 70, "height_left": 100, "height_right": 100, "margin_low": 7, "margin_up": 4, "length": 100},
]
# Créer un DataFrame à partir des données à ajouter
Data_sup = pd.DataFrame(data_to_append)
# Ajouter les lignes au DataFrame existant
DF_Test = pd.concat([DF_Test, Data_sup], ignore_index=True)
# Ajout d'une colonne 'Id'
n = len(DF_Test)
DF_Test.insert(0, 'Id', [f'B-{i}' for i in range(1, n+1)])
#Tmessage("Fichier test")
#display(DF_Test.head())
#display(DF_Test.shape)
DF_Verif = DF_Test.copy()
DF_Test1 = DF_Test.copy()
DF_T = pd.read_csv('Fichier_test_Mentor.csv', sep=";")
DF_T = DF_T[["diagonal", "height_left", "height_right", "margin_low", "margin_up", "length"]]
DF_Test1 = DF_Test1.drop(['is_genuine','Id'], axis=1)
DF_Test1 = pd.concat([DF_Test1, DF_T])
DF_Test1 = DF_Test1.reset_index(drop=True)
# Ajout d'une colonne 'Id'
n = len(DF_Test1)
DF_Test1.insert(0, 'Id', [f'B-{i}' for i in range(1, n+1)])
Avec Statsmodels
DF_T = pd.read_csv('billets_testN.csv')
detection_faux_billets_SM(DF_T)
Optimization terminated successfully.
Current function value: 0.029939
Iterations 11
| diagonal | height_left | height_right | margin_low | margin_up | length | id | |
|---|---|---|---|---|---|---|---|
| 0 | 172.09 | 103.95 | 103.73 | 4.39 | 3.09 | 113.19 | B_1 |
| 1 | 171.52 | 104.17 | 104.03 | 5.27 | 3.16 | 111.82 | B_2 |
| 2 | 171.78 | 103.80 | 103.75 | 3.81 | 3.24 | 113.39 | B_3 |
| 3 | 172.02 | 104.08 | 103.99 | 5.57 | 3.30 | 111.10 | B_4 |
| 4 | 171.79 | 104.34 | 104.37 | 5.00 | 3.07 | 111.87 | B_5 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 172.09 | 103.95 | 103.73 | 4.39 | 3.09 | 113.19 |
| 1 | 171.52 | 104.17 | 104.03 | 5.27 | 3.16 | 111.82 |
| 2 | 171.78 | 103.80 | 103.75 | 3.81 | 3.24 | 113.39 |
| is_genuine_Predict | % Probablement VRAI | diagonal | height_left | height_right | margin_low | margin_up | length | id | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 99.930000 | 172.090000 | 103.950000 | 103.730000 | 4.390000 | 3.090000 | 113.190000 | B_1 |
| 1 | 0 | 0.050000 | 171.520000 | 104.170000 | 104.030000 | 5.270000 | 3.160000 | 111.820000 | B_2 |
| 2 | 1 | 100.000000 | 171.780000 | 103.800000 | 103.750000 | 3.810000 | 3.240000 | 113.390000 | B_3 |
| 3 | 0 | 0.000000 | 172.020000 | 104.080000 | 103.990000 | 5.570000 | 3.300000 | 111.100000 | B_4 |
| 4 | 0 | 0.140000 | 171.790000 | 104.340000 | 104.370000 | 5.000000 | 3.070000 | 111.870000 | B_5 |
Avec Sklearn
DF_T = pd.read_csv('billets_testN.csv')
detection_faux_billets_SK(DF_T)
| diagonal | height_left | height_right | margin_low | margin_up | length | id | |
|---|---|---|---|---|---|---|---|
| 0 | 172.09 | 103.95 | 103.73 | 4.39 | 3.09 | 113.19 | B_1 |
| 1 | 171.52 | 104.17 | 104.03 | 5.27 | 3.16 | 111.82 | B_2 |
| 2 | 171.78 | 103.80 | 103.75 | 3.81 | 3.24 | 113.39 | B_3 |
| 3 | 172.02 | 104.08 | 103.99 | 5.57 | 3.30 | 111.10 | B_4 |
| 4 | 171.79 | 104.34 | 104.37 | 5.00 | 3.07 | 111.87 | B_5 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 172.09 | 103.95 | 103.73 | 4.39 | 3.09 | 113.19 |
| 1 | 171.52 | 104.17 | 104.03 | 5.27 | 3.16 | 111.82 |
| 2 | 171.78 | 103.80 | 103.75 | 3.81 | 3.24 | 113.39 |
| is_genuine_Predict | % Probablement VRAI | diagonal | height_left | height_right | margin_low | margin_up | length | id | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 98.950000 | 172.090000 | 103.950000 | 103.730000 | 4.390000 | 3.090000 | 113.190000 | B_1 |
| 1 | 0 | 1.340000 | 171.520000 | 104.170000 | 104.030000 | 5.270000 | 3.160000 | 111.820000 | B_2 |
| 2 | 1 | 99.890000 | 171.780000 | 103.800000 | 103.750000 | 3.810000 | 3.240000 | 113.390000 | B_3 |
| 3 | 0 | 0.030000 | 172.020000 | 104.080000 | 103.990000 | 5.570000 | 3.300000 | 111.100000 | B_4 |
| 4 | 0 | 1.740000 | 171.790000 | 104.340000 | 104.370000 | 5.000000 | 3.070000 | 111.870000 | B_5 |
Test avec un fichier non conforme
DF_T = pd.read_csv('Fichier_test_Mentor.csv', sep=";")
detection_faux_billets_SM(DF_T)
Optimization terminated successfully.
Current function value: 0.029939
Iterations 11
| diagonal | height_left | height_right | margin_low | margin_up | length | id | |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0.00 | 0.00 | 0.00 | 0.00 | B_1 |
| 1 | Az | R | 104.03 | 5.27 | 3.16 | 111.82 | B_2 |
| 2 | 100 | 50 | 103.75 | 3.81 | 3.24 | 113.39 | B_3 |
| 3 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 | B_4 |
| 4 | 999 | 999 | 104.37 | 5.00 | 3.07 | 111.87 | B_5 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0.00 | 0.00 | 0.00 | 0.00 |
| 1 | Az | R | 104.03 | 5.27 | 3.16 | 111.82 |
| 2 | 100 | 50 | 103.75 | 3.81 | 3.24 | 113.39 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0.0 | 0.0 | 0.0 | 0.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 6 | NaN | NaN | 104.37 | 5.0 | 3.07 | 111.87 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 1 | Az | R | 104.03 | 5.27 | 3.16 | 111.82 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 2 | 100.0000 | 50.0000 | 103.75 | 3.81 | 3.24 | 113.39 |
| 3 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 |
| 4 | 999.0000 | 999.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| 5 | 345.0000 | 435.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 2 | 100.0000 | 50.0000 | 103.75 | 3.81 | 3.24 | 113.39 |
| 3 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 |
| 4 | 999.0000 | 999.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| 5 | 345.0000 | 435.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
Test avec le fichier généré
detection_faux_billets_SM(DF_Test)
Optimization terminated successfully.
Current function value: 0.029939
Iterations 11
| Id | is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|---|
| 0 | B-1 | 1 | 172.63 | 104.13 | 104.17 | 3.77 | 3.45 | 113.34 |
| 1 | B-2 | 0 | 172.40 | 104.55 | 104.22 | 5.18 | 3.51 | 111.94 |
| 2 | B-3 | 0 | 171.91 | 103.99 | 104.23 | 5.01 | 3.42 | 111.77 |
| 3 | B-4 | 0 | 171.21 | 104.29 | 104.41 | 5.14 | 3.26 | 111.16 |
| 4 | B-5 | 1 | 171.87 | 104.29 | 103.53 | 3.91 | 2.89 | 112.91 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 172.63 | 104.13 | 104.17 | 3.77 | 3.45 | 113.34 |
| 1 | 172.40 | 104.55 | 104.22 | 5.18 | 3.51 | 111.94 |
| 2 | 171.91 | 103.99 | 104.23 | 5.01 | 3.42 | 111.77 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 20 | 172.00 | 0.00 | 103.59 | 4.08 | 0.00 | 114.09 |
| 24 | 500.85 | 103.93 | 103.81 | 0.00 | 3.12 | 112.80 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 27 | 800.0 | 500.0 | 300.0 | 40.0 | 50.0 | 800.0 |
| 28 | 70.0 | 100.0 | 100.0 | 7.0 | 4.0 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 25 | 171.85 | 20.0 | 103.81 | 4.0 | 30.12 | 112.8 |
| 27 | 800.00 | 500.0 | 300.00 | 40.0 | 50.00 | 800.0 |
| 28 | 70.00 | 100.0 | 100.00 | 7.0 | 4.00 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 22 | 172.58 | 103.99 | 150.0 | 4.43 | 3.07 | 112.79 |
| 27 | 800.00 | 500.00 | 300.0 | 40.00 | 50.00 | 800.00 |
| 28 | 70.00 | 100.00 | 100.0 | 7.00 | 4.00 | 100.00 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 26 | 171.85 | 103.93 | 103.81 | 40.0 | 3.12 | 112.8 |
| 27 | 800.00 | 500.00 | 300.00 | 40.0 | 50.00 | 800.0 |
| 28 | 70.00 | 100.00 | 100.00 | 7.0 | 4.00 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 25 | 171.85 | 20.0 | 103.81 | 4.0 | 30.12 | 112.8 |
| 27 | 800.00 | 500.0 | 300.00 | 40.0 | 50.00 | 800.0 |
| 28 | 70.00 | 100.0 | 100.00 | 7.0 | 4.00 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 21 | 172.0 | 104.35 | 103.29 | 3.73 | 3.11 | 999.18 |
| 27 | 800.0 | 500.00 | 300.00 | 40.00 | 50.00 | 800.00 |
| 28 | 70.0 | 100.00 | 100.00 | 7.00 | 4.00 | 100.00 |
| is_genuine_Predict | % Probablement VRAI | Id | is_genuine | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 99.840000 | B-1 | 1 | 172.630000 | 104.130000 | 104.170000 | 3.770000 | 3.450000 | 113.340000 |
| 1 | 0 | 0.000000 | B-2 | 0 | 172.400000 | 104.550000 | 104.220000 | 5.180000 | 3.510000 | 111.940000 |
| 2 | 0 | 0.010000 | B-3 | 0 | 171.910000 | 103.990000 | 104.230000 | 5.010000 | 3.420000 | 111.770000 |
| 3 | 0 | 0.000000 | B-4 | 0 | 171.210000 | 104.290000 | 104.410000 | 5.140000 | 3.260000 | 111.160000 |
| 4 | 1 | 100.000000 | B-5 | 1 | 171.870000 | 104.290000 | 103.530000 | 3.910000 | 2.890000 | 112.910000 |
| 5 | 1 | 99.260000 | B-6 | 1 | 171.360000 | 103.720000 | 104.760000 | 4.170000 | 2.880000 | 113.140000 |
| 6 | 0 | 0.010000 | B-7 | 0 | 172.310000 | 104.310000 | 104.720000 | 4.860000 | 3.410000 | 112.060000 |
| 7 | 1 | 99.990000 | B-8 | 1 | 171.790000 | 103.510000 | 103.250000 | 4.050000 | 3.080000 | 112.710000 |
| 8 | 1 | 99.990000 | B-9 | 1 | 172.520000 | 103.900000 | 104.030000 | 3.970000 | 2.980000 | 113.300000 |
| 9 | 1 | 100.000000 | B-10 | 1 | 171.870000 | 103.940000 | 103.220000 | 3.710000 | 3.090000 | 113.190000 |
| 10 | 0 | 0.000000 | B-11 | 0 | 171.960000 | 104.450000 | 104.480000 | 5.310000 | 3.420000 | 111.750000 |
| 11 | 1 | 99.920000 | B-12 | 1 | 172.020000 | 104.070000 | 104.130000 | 3.720000 | 2.960000 | 112.560000 |
| 12 | 1 | 100.000000 | B-13 | 1 | 171.650000 | 103.880000 | 103.590000 | 3.940000 | 3.050000 | 113.280000 |
| 13 | 0 | 0.010000 | B-14 | 0 | 172.410000 | 104.320000 | 103.930000 | 5.820000 | 3.360000 | 112.360000 |
| 14 | 0 | 0.000000 | B-15 | 0 | 172.050000 | 104.220000 | 104.050000 | 5.870000 | 3.180000 | 111.130000 |
| 15 | 1 | 99.910000 | B-16 | 1 | 171.410000 | 104.030000 | 104.210000 | 4.260000 | 3.110000 | 113.490000 |
| 16 | 1 | 99.340000 | B-17 | 1 | 171.770000 | 103.920000 | 103.900000 | 4.610000 | 2.950000 | 112.950000 |
| 17 | 1 | 98.090000 | B-18 | 1 | 171.950000 | 103.440000 | 103.800000 | 4.080000 | 3.190000 | 112.430000 |
| 18 | 1 | 99.990000 | B-19 | 1 | 172.280000 | 103.630000 | 103.970000 | 3.790000 | 2.940000 | 112.900000 |
| 19 | 1 | 100.000000 | B-20 | 1 | 172.110000 | 104.120000 | 103.830000 | 3.900000 | 2.720000 | 113.280000 |
| 23 | 1 | 99.910000 | B-24 | 0 | 171.850000 | 103.930000 | 103.810000 | 4.000000 | 3.120000 | 112.800000 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 20 | 172.00 | 0.00 | 103.59 | 4.08 | 0.00 | 114.09 | B-21 |
| 24 | 500.85 | 103.93 | 103.81 | 0.00 | 3.12 | 112.80 | B-25 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id |
|---|
| diagonal | height_left | height_right | margin_low | margin_up | length | Id |
|---|
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 0 | 800.00 | 500.00 | 300.00 | 40.00 | 50.00 | 800.00 | B-1 |
| 1 | 70.00 | 100.00 | 100.00 | 7.00 | 4.00 | 100.00 | B-2 |
| 2 | 171.85 | 20.00 | 103.81 | 4.00 | 30.12 | 112.80 | B-3 |
| 5 | 172.58 | 103.99 | 150.00 | 4.43 | 3.07 | 112.79 | B-6 |
| 8 | 171.85 | 103.93 | 103.81 | 40.00 | 3.12 | 112.80 | B-9 |
| 14 | 172.00 | 104.35 | 103.29 | 3.73 | 3.11 | 999.18 | B-15 |
Test avec le fichier généré + fichier non conforme
detection_faux_billets_SM(DF_Test1)
Optimization terminated successfully.
Current function value: 0.029939
Iterations 11
| Id | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|
| 0 | B-1 | 172.63 | 104.13 | 104.17 | 3.77 | 3.45 | 113.34 |
| 1 | B-2 | 172.4 | 104.55 | 104.22 | 5.18 | 3.51 | 111.94 |
| 2 | B-3 | 171.91 | 103.99 | 104.23 | 5.01 | 3.42 | 111.77 |
| 3 | B-4 | 171.21 | 104.29 | 104.41 | 5.14 | 3.26 | 111.16 |
| 4 | B-5 | 171.87 | 104.29 | 103.53 | 3.91 | 2.89 | 112.91 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 0 | 172.63 | 104.13 | 104.17 | 3.77 | 3.45 | 113.34 |
| 1 | 172.4 | 104.55 | 104.22 | 5.18 | 3.51 | 111.94 |
| 2 | 171.91 | 103.99 | 104.23 | 5.01 | 3.42 | 111.77 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 20 | 172.0 | 0.0 | 103.59 | 4.08 | 0.00 | 114.09 |
| 24 | 500.85 | 103.93 | 103.81 | 0.00 | 3.12 | 112.80 |
| 29 | 0 | 0 | 0.00 | 0.00 | 0.00 | 0.00 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 35 | NaN | NaN | 104.37 | 5.0 | 3.07 | 111.87 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 30 | Az | R | 104.03 | 5.27 | 3.16 | 111.82 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 27 | 800.0000 | 500.0000 | 300.00 | 40.00 | 50.00 | 800.00 |
| 28 | 70.0000 | 100.0000 | 100.00 | 7.00 | 4.00 | 100.00 |
| 31 | 100.0000 | 50.0000 | 103.75 | 3.81 | 3.24 | 113.39 |
| 32 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 |
| 33 | 999.0000 | 999.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| 34 | 345.0000 | 435.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 25 | 171.8500 | 20.0000 | 103.81 | 4.00 | 30.12 | 112.80 |
| 27 | 800.0000 | 500.0000 | 300.00 | 40.00 | 50.00 | 800.00 |
| 28 | 70.0000 | 100.0000 | 100.00 | 7.00 | 4.00 | 100.00 |
| 31 | 100.0000 | 50.0000 | 103.75 | 3.81 | 3.24 | 113.39 |
| 32 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 |
| 33 | 999.0000 | 999.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| 34 | 345.0000 | 435.0000 | 104.37 | 5.00 | 3.07 | 111.87 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 22 | 172.58 | 103.99 | 150.0 | 4.43 | 3.07 | 112.79 |
| 27 | 800.00 | 500.00 | 300.0 | 40.00 | 50.00 | 800.00 |
| 28 | 70.00 | 100.00 | 100.0 | 7.00 | 4.00 | 100.00 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 26 | 171.85 | 103.93 | 103.81 | 40.0 | 3.12 | 112.8 |
| 27 | 800.00 | 500.00 | 300.00 | 40.0 | 50.00 | 800.0 |
| 28 | 70.00 | 100.00 | 100.00 | 7.0 | 4.00 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 25 | 171.85 | 20.0 | 103.81 | 4.0 | 30.12 | 112.8 |
| 27 | 800.00 | 500.0 | 300.00 | 40.0 | 50.00 | 800.0 |
| 28 | 70.00 | 100.0 | 100.00 | 7.0 | 4.00 | 100.0 |
| diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|
| 21 | 172.0 | 104.35 | 103.29 | 3.73 | 3.11 | 999.18 |
| 27 | 800.0 | 500.00 | 300.00 | 40.00 | 50.00 | 800.00 |
| 28 | 70.0 | 100.00 | 100.00 | 7.00 | 4.00 | 100.00 |
| is_genuine_Predict | % Probablement VRAI | Id | diagonal | height_left | height_right | margin_low | margin_up | length | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 99.840000 | B-1 | 172.630000 | 104.130000 | 104.170000 | 3.770000 | 3.450000 | 113.340000 |
| 1 | 0 | 0.000000 | B-2 | 172.400000 | 104.550000 | 104.220000 | 5.180000 | 3.510000 | 111.940000 |
| 2 | 0 | 0.010000 | B-3 | 171.910000 | 103.990000 | 104.230000 | 5.010000 | 3.420000 | 111.770000 |
| 3 | 0 | 0.000000 | B-4 | 171.210000 | 104.290000 | 104.410000 | 5.140000 | 3.260000 | 111.160000 |
| 4 | 1 | 100.000000 | B-5 | 171.870000 | 104.290000 | 103.530000 | 3.910000 | 2.890000 | 112.910000 |
| 5 | 1 | 99.260000 | B-6 | 171.360000 | 103.720000 | 104.760000 | 4.170000 | 2.880000 | 113.140000 |
| 6 | 0 | 0.010000 | B-7 | 172.310000 | 104.310000 | 104.720000 | 4.860000 | 3.410000 | 112.060000 |
| 7 | 1 | 99.990000 | B-8 | 171.790000 | 103.510000 | 103.250000 | 4.050000 | 3.080000 | 112.710000 |
| 8 | 1 | 99.990000 | B-9 | 172.520000 | 103.900000 | 104.030000 | 3.970000 | 2.980000 | 113.300000 |
| 9 | 1 | 100.000000 | B-10 | 171.870000 | 103.940000 | 103.220000 | 3.710000 | 3.090000 | 113.190000 |
| 10 | 0 | 0.000000 | B-11 | 171.960000 | 104.450000 | 104.480000 | 5.310000 | 3.420000 | 111.750000 |
| 11 | 1 | 99.920000 | B-12 | 172.020000 | 104.070000 | 104.130000 | 3.720000 | 2.960000 | 112.560000 |
| 12 | 1 | 100.000000 | B-13 | 171.650000 | 103.880000 | 103.590000 | 3.940000 | 3.050000 | 113.280000 |
| 13 | 0 | 0.010000 | B-14 | 172.410000 | 104.320000 | 103.930000 | 5.820000 | 3.360000 | 112.360000 |
| 14 | 0 | 0.000000 | B-15 | 172.050000 | 104.220000 | 104.050000 | 5.870000 | 3.180000 | 111.130000 |
| 15 | 1 | 99.910000 | B-16 | 171.410000 | 104.030000 | 104.210000 | 4.260000 | 3.110000 | 113.490000 |
| 16 | 1 | 99.340000 | B-17 | 171.770000 | 103.920000 | 103.900000 | 4.610000 | 2.950000 | 112.950000 |
| 17 | 1 | 98.090000 | B-18 | 171.950000 | 103.440000 | 103.800000 | 4.080000 | 3.190000 | 112.430000 |
| 18 | 1 | 99.990000 | B-19 | 172.280000 | 103.630000 | 103.970000 | 3.790000 | 2.940000 | 112.900000 |
| 19 | 1 | 100.000000 | B-20 | 172.110000 | 104.120000 | 103.830000 | 3.900000 | 2.720000 | 113.280000 |
| 23 | 1 | 99.910000 | B-24 | 171.850000 | 103.930000 | 103.810000 | 4.000000 | 3.120000 | 112.800000 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 20 | 172.0 | 0.0 | 103.59 | 4.08 | 0.00 | 114.09 | B-21 |
| 24 | 500.85 | 103.93 | 103.81 | 0.00 | 3.12 | 112.80 | B-25 |
| 29 | 0 | 0 | 0.00 | 0.00 | 0.00 | 0.00 | B-30 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 30 | Az | R | 104.03 | 5.27 | 3.16 | 111.82 | B-31 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 35 | NaN | NaN | 104.37 | 5.0 | 3.07 | 111.87 | B-36 |
| diagonal | height_left | height_right | margin_low | margin_up | length | Id | |
|---|---|---|---|---|---|---|---|
| 0 | 800.0000 | 500.0000 | 300.00 | 40.00 | 50.00 | 800.00 | B-1 |
| 1 | 70.0000 | 100.0000 | 100.00 | 7.00 | 4.00 | 100.00 | B-2 |
| 2 | 100.0000 | 50.0000 | 103.75 | 3.81 | 3.24 | 113.39 | B-3 |
| 3 | 0.0001 | 0.0001 | 103.99 | 5.57 | 3.30 | 111.10 | B-4 |
| 4 | 999.0000 | 999.0000 | 104.37 | 5.00 | 3.07 | 111.87 | B-5 |
| 5 | 345.0000 | 435.0000 | 104.37 | 5.00 | 3.07 | 111.87 | B-6 |
| 6 | 171.8500 | 20.0000 | 103.81 | 4.00 | 30.12 | 112.80 | B-7 |
| 13 | 172.5800 | 103.9900 | 150.00 | 4.43 | 3.07 | 112.79 | B-14 |
| 16 | 171.8500 | 103.9300 | 103.81 | 40.00 | 3.12 | 112.80 | B-17 |
| 22 | 172.0000 | 104.3500 | 103.29 | 3.73 | 3.11 | 999.18 | B-23 |
# Statsmodels à 0 = 0.99903
# Sklearn à 0 = 0.9920505
Seuil = 0.8
test_size = 0.3
V_pred = ["height_right", "margin_low", "margin_up", "length"]
Acceptation_Seuil(DF_F, Seuil = Seuil, test_size = test_size, V_pred = V_pred)
Optimization terminated successfully.
Current function value: 0.035116
Iterations 11
Le modèle de régression logistique de Statsmodels obtient de meilleurs performances dans la détection de faux billets pour la plupart des seuils